From ce1a4b6e32c271b8f2a92693bdc4f924495ea5e0 Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Wed, 27 Nov 2024 10:20:40 -0500 Subject: [PATCH] test(invocation): verify arguments versus aggregated policies --- pkg/policy/match_test.go | 55 ---------- pkg/policy/policytest/example.go | 98 ++++++++++++++++++ pkg/policy/policytest/example_test.go | 32 ++++++ .../data/TokenCarolDan_InvalidExpired.dagcbor | Bin 337 -> 337 bytes .../TokenCarolDan_ValidExamplePolicy.dagcbor | Bin 0 -> 392 bytes .../data/TokenDanErin_InvalidExpired.dagcbor | Bin 337 -> 337 bytes .../TokenDanErin_ValidExamplePolicy.dagcbor | Bin 0 -> 392 bytes .../TokenErinFrank_InvalidExpired.dagcbor | Bin 337 -> 337 bytes .../TokenErinFrank_ValidExamplePolicy.dagcbor | Bin 0 -> 392 bytes .../delegationtest/generator/generator.go | 6 +- token/delegation/delegationtest/token_gen.go | 42 +++++++- token/invocation/errors.go | 4 + token/invocation/invocation_test.go | 22 +++- token/invocation/proof.go | 2 +- 14 files changed, 200 insertions(+), 61 deletions(-) create mode 100644 pkg/policy/policytest/example.go create mode 100644 pkg/policy/policytest/example_test.go create mode 100644 token/delegation/delegationtest/data/TokenCarolDan_ValidExamplePolicy.dagcbor create mode 100644 token/delegation/delegationtest/data/TokenDanErin_ValidExamplePolicy.dagcbor create mode 100644 token/delegation/delegationtest/data/TokenErinFrank_ValidExamplePolicy.dagcbor diff --git a/pkg/policy/match_test.go b/pkg/policy/match_test.go index 6a85512..108037a 100644 --- a/pkg/policy/match_test.go +++ b/pkg/policy/match_test.go @@ -7,11 +7,8 @@ import ( "github.com/ipfs/go-cid" "github.com/ipld/go-ipld-prime" "github.com/ipld/go-ipld-prime/codec/dagjson" - "github.com/ipld/go-ipld-prime/datamodel" - "github.com/ipld/go-ipld-prime/fluent/qp" cidlink "github.com/ipld/go-ipld-prime/linking/cid" "github.com/ipld/go-ipld-prime/node/basicnode" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/ucan-wg/go-ucan/pkg/policy/literal" @@ -904,55 +901,3 @@ func TestPartialMatch(t *testing.T) { }) } } - -// TestInvocationValidation applies the example policy to the second -// example arguments as defined in the [Validation] section of the -// invocation specification. -// -// [Validation]: https://github.com/ucan-wg/delegation/tree/v1_ipld#validation -func TestInvocationValidationSpecExamples(t *testing.T) { - t.Parallel() - - pol := MustConstruct( - Equal(".from", literal.String("alice@example.com")), - Any(".to", Like(".", "*@example.com")), - ) - - t.Run("with passing args", func(t *testing.T) { - t.Parallel() - - argsNode, err := qp.BuildMap(basicnode.Prototype.Any, 2, func(ma datamodel.MapAssembler) { - qp.MapEntry(ma, "from", qp.String("alice@example.com")) - qp.MapEntry(ma, "to", qp.List(2, func(la datamodel.ListAssembler) { - qp.ListEntry(la, qp.String("bob@example.com")) - qp.ListEntry(la, qp.String("carol@not.example.com")) - })) - qp.MapEntry(ma, "title", qp.String("Coffee")) - qp.MapEntry(ma, "body", qp.String("Still on for coffee")) - }) - require.NoError(t, err) - - exec, stmt := pol.Match(argsNode) - assert.True(t, exec) - assert.Nil(t, stmt) - }) - - t.Run("fails on recipients (second statement)", func(t *testing.T) { - t.Parallel() - - argsNode, err := qp.BuildMap(basicnode.Prototype.Any, 2, func(ma datamodel.MapAssembler) { - qp.MapEntry(ma, "from", qp.String("alice@example.com")) - qp.MapEntry(ma, "to", qp.List(2, func(la datamodel.ListAssembler) { - qp.ListEntry(la, qp.String("bob@null.com")) - qp.ListEntry(la, qp.String("carol@elsewhere.example.com")) - })) - qp.MapEntry(ma, "title", qp.String("Coffee")) - qp.MapEntry(ma, "body", qp.String("Still on for coffee")) - }) - require.NoError(t, err) - - exec, stmt := pol.Match(argsNode) - assert.False(t, exec) - assert.NotNil(t, stmt) - }) -} diff --git a/pkg/policy/policytest/example.go b/pkg/policy/policytest/example.go new file mode 100644 index 0000000..e9d20c6 --- /dev/null +++ b/pkg/policy/policytest/example.go @@ -0,0 +1,98 @@ +package policytest + +import ( + "errors" + + "github.com/ipld/go-ipld-prime" + "github.com/ucan-wg/go-ucan/pkg/args" + "github.com/ucan-wg/go-ucan/pkg/policy" + "github.com/ucan-wg/go-ucan/pkg/policy/literal" +) + +// EmptyPolicy provides a Policy with no statements. +var EmptyPolicy = policy.Policy{} + +// ExampleValidationPolicy provides a instantiated Policy containing the +// statements that are included in the second code block of the [Validation] +// section of the delegation specification. +// +// [Validation]: https://github.com/ucan-wg/delegation/tree/v1_ipld#validation +var ExamplePolicy = policy.MustConstruct( + policy.Equal(".from", literal.String("alice@example.com")), + policy.Any(".to", policy.Like(".", "*@example.com")), +) + +// TODO: Replace the URL for [Validation] above when the delegation +// specification has been finished/merged. + +// ExampleValidArguments provides valid, instantiated Arguments containing +// the key/value pairs that are included in portion of the the second code +// block of the [Validation] section of the delegation specification. +// +// [Validation]: https://github.com/ucan-wg/delegation/tree/v1_ipld#validation +var ExampleValidArguments = newBuilder(nil). + add("from", "alice@example.com"). + add("to", []string{ + "bob@example.com", + "carol@not.example.com", + }). + add("title", "Coffee"). + add("body", "Still on for coffee"). + mustBuild() + +var exampleValidArgumentsIPLD = mustIPLD(ExampleValidArguments) + +// ExampleInvalidArguments provides invalid, instantiated Arguments containing +// the key/value pairs that are included in portion of the the second code +// block of the [Validation] section of the delegation specification. +// +// [Validation]: https://github.com/ucan-wg/delegation/tree/v1_ipld#validation +var ExampleInvalidArguments = newBuilder(nil). + add("from", "alice@example.com"). + add("to", []string{ + "bob@null.com", + "carol@elsewhere.example.com", + }). + add("title", "Coffee"). + add("body", "Still on for coffee"). + mustBuild() + +var exampleInvalidArgumentsIPLD = mustIPLD(ExampleInvalidArguments) + +type builder struct { + args *args.Args + errs error +} + +func newBuilder(a *args.Args) *builder { + if a == nil { + a = args.New() + } + + return &builder{ + args: a, + } +} + +func (b *builder) add(key string, val any) *builder { + b.errs = errors.Join(b.errs, b.args.Add(key, val)) + + return b +} + +func (b *builder) mustBuild() *args.Args { + if b.errs != nil { + panic(b.errs) + } + + return b.args +} + +func mustIPLD(args *args.Args) ipld.Node { + node, err := args.ToIPLD() + if err != nil { + panic(err) + } + + return node +} diff --git a/pkg/policy/policytest/example_test.go b/pkg/policy/policytest/example_test.go new file mode 100644 index 0000000..4025d8a --- /dev/null +++ b/pkg/policy/policytest/example_test.go @@ -0,0 +1,32 @@ +package policytest + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// TestInvocationValidation applies the example policy to the second +// example arguments as defined in the [Validation] section of the +// invocation specification. +// +// [Validation]: https://github.com/ucan-wg/delegation/tree/v1_ipld#validation +func TestInvocationValidationSpecExamples(t *testing.T) { + t.Parallel() + + t.Run("with passing args", func(t *testing.T) { + t.Parallel() + + exec, stmt := ExamplePolicy.Match(exampleValidArgumentsIPLD) + assert.True(t, exec) + assert.Nil(t, stmt) + }) + + t.Run("fails on recipients (second statement)", func(t *testing.T) { + t.Parallel() + + exec, stmt := ExamplePolicy.Match(exampleInvalidArgumentsIPLD) + assert.False(t, exec) + assert.NotNil(t, stmt) + }) +} diff --git a/token/delegation/delegationtest/data/TokenCarolDan_InvalidExpired.dagcbor b/token/delegation/delegationtest/data/TokenCarolDan_InvalidExpired.dagcbor index c67b5e2230da340ac9a723647aba761bd0ef6416..2c3342fa3d8f802047b4e5d1bb77264690acbe18 100644 GIT binary patch delta 82 zcmV-Y0ImPg0?`6Pf>=PlQ(_1P7cMc-f-o~buZJA_jmXH0m1N+PBp^>U6{ue$5v=wl oJBqggsyqW2aWAjd3v`u+h41(qGLqfq9vcCXLw5s5EuWFSlv<)8_y7O^ delta 82 zcmV-Y0ImPg0?`6Pf>=QB-LYur9%I8H23sWV5wztv=do-3)y#*hyg{zP+9dotSdzWN oUdbQa&@i6{yF`LTO%AlDMqc&@n^IUbDP;qZLw5r`=}nQnl)&UC`2YX_ diff --git a/token/delegation/delegationtest/data/TokenCarolDan_ValidExamplePolicy.dagcbor b/token/delegation/delegationtest/data/TokenCarolDan_ValidExamplePolicy.dagcbor new file mode 100644 index 0000000000000000000000000000000000000000..d53ec6b62ef3ced3a2a24e3b02b73a601d442094 GIT binary patch literal 392 zcmZpQaFBddZFxcMzyp~Nj|v&p&wQD1fb07eakH|DeMT>(b{ZZ3n5w|<^B}wKB}0eB z;;Qt&$#ed{Xq27vM5D&9yU3A^Wl>^=i^*HY!s628#610!oOB06Jp(-h-J)bY!{y0| zr70B_DVZr&*{PLQRc5}~c}eD#Sw8uRm8R~AUOw3tm4>cnX88fx&W>iOS;pCp=Be2h zS*E!`rUlu_$;r7Xh5D%#1&MhnsVVw-`MH^Si8;wYfp5u~#l@%wr9vk8u}Jl6c}ZC`vqlGmIapuITl;yB^Tu9G&LvL+NSEI73Jp^Cgx-& zr#hroB<2?6r0ON-=QacVQkkq*lHZ(?lbM~GsF$mSES+3jnuKb5X=!%0QE|3Qgim0e zxu3VOYldZ(Z(d4dTA7PeMMZW=dO>E2mt$d)xvz0SYF>U`a;gslBNH=PoH%tlh7$YfoX9Q?7O}goc(J$)vFqOi)*)#iD(8w5vp1VDe oqx~dVH=Pb4Wvw(C4AC$By^CP`W-LweSGHT%3Gl&QI^IhUZ%s zx6hAzvp>Hx^^w=K;ct7UtczxeUK55#5^fh(~s`=Dsf6WgdU6Xn7|vC})LIU_vDoSmwG$!)9pg^4-)H%E{0}Nr5V4T_vxUf5PpzZs;VrD6kqjM0Y*FaGxnMf?iGT$UCnv5NZXbL77 zCr!809)Zx~ZmVrAEn%Tt=d=b~8)6lQfO;+#AgAr_mk0_6yp3F&U?9-B{}}p#)msk& zLXtkom-H>BY^+O#YSu9rGRuwpau||>if5yuR=QH^~X6y^Cr!#m&*rTcWk?O#6yW2@K0&IwH5#0S#Db=r7age o8gDiM>?!roK90T9?KABF)i}T+=w&OjtaApDLw5s5EuWFSlzzS^P5=M^ delta 82 zcmV-Y0ImPg0?`6Pf>=Pyw`)5n{VvL}qo9nLr~$@Gg~}i@1Q=WV?Ts+BU3dUL$+twB o!G1NVFwQlHp1bxAo(SV7_k{NSZLB#hI^F=0Lw5r`=}nQnlvR8uivR!s diff --git a/token/delegation/delegationtest/data/TokenErinFrank_ValidExamplePolicy.dagcbor b/token/delegation/delegationtest/data/TokenErinFrank_ValidExamplePolicy.dagcbor new file mode 100644 index 0000000000000000000000000000000000000000..7a6f5412369c9586bf0cd26652643e94ef3e0f0a GIT binary patch literal 392 zcmZpQaA=Qnt0@bSOjsNzpX+$%n0o&Vp-1v7FJ-S#nw;&SCtr6uqI+pc(4;?m^AJpGiMbO%E{13d%XqGUb8<;jVq zDHRqenJHG;sg+h$X1>{(7UdCcq2Yy=#-T~&S%Ha#6_L(vZpq1|sSzn<-afhI!5(Q9 zzTQ5@0q)Mp$+;wYA=42+P zI;2)4<`(3n>LusrHUs@qnXFfm-<*<@nVp)bm#c*=om^a+glc