// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: MIT package rpc import ( "testing" "sourcedock.dev/petrbalvin/nfs/internal/xdr" ) // The RPCSEC_GSSv3 credential round trips with the version field in // front, RFC 7861 section 5.1. func TestGSSv3CredShape(t *testing.T) { body := AppendGSSv3Cred(nil, GSSProcCreate, 7, SvcPrivacy, []byte("parent")) cred, err := DecodeGSSv3Cred(body) if err != nil { t.Fatal(err) } if cred.Proc != GSSProcCreate || cred.Seq != 7 || cred.Service != SvcPrivacy || string(cred.Handle) != "parent" { t.Fatalf("cred %+v", cred) } if _, err := DecodeGSSv3Cred(append([]byte{0, 0, 0, 1}, body[4:]...)); err != ErrGSSv3 { t.Fatalf("version one body accepted: %v", err) } } // The create arguments and reply round trip through their codecs, // including the optional fields and the assertion union. func TestGSSv3CreateShapes(t *testing.T) { args := AppendCreateArgs(nil, &MpAuth{InnerHandle: []byte("inner"), HeaderMic: []byte("mic")}, []byte("binding"), []Assertion{ {Type: AssertionLabel, Label: Label{LfsId: 1, PiId: 2, Bytes: []byte("secret")}}, {Type: AssertionPrivs, Privs: Privs{Who: "petr", Grant: "admin", Bytes: []byte("x")}}, {Type: 9, Ext: []byte("ext")}, }) mp, bind, assertions, err := DecodeCreateArgs(args) if err != nil { t.Fatal(err) } if mp == nil || string(mp.InnerHandle) != "inner" || string(mp.HeaderMic) != "mic" { t.Fatalf("mp auth %+v", mp) } if string(bind) != "binding" { t.Fatalf("binding %q", bind) } if len(assertions) != 3 || assertions[0].Label.LfsId != 1 || assertions[1].Privs.Who != "petr" || assertions[2].Ext == nil { t.Fatalf("assertions %+v", assertions) } // The reply mirrors the shape with the child handle. res := AppendCreateRes(nil, []byte("child"), nil, nil, []Assertion{{Type: AssertionLabel, Label: Label{LfsId: 1, Bytes: []byte("secret")}}}) handle, _, _, granted, err := DecodeCreateRes(res) if err != nil { t.Fatal(err) } if string(handle) != "child" || len(granted) != 1 { t.Fatalf("res handle %q granted %d", handle, len(granted)) } // The list reply carries the type array. list := AppendListRes(nil, []uint32{AssertionLabel, AssertionPrivs}) d := xdr.NewDecoder(list) n, err := d.Uint32() if err != nil || n != 2 { t.Fatalf("list count %d: %v", n, err) } t1, _ := d.Uint32() t2, _ := d.Uint32() if t1 != AssertionLabel || t2 != AssertionPrivs { t.Fatalf("list types %d %d", t1, t2) } }