security_test.gno
3.99 Kb · 106 lines
1package gns
2
3import (
4 "testing"
5)
6
7// This file targets the "critical invariants" list from the spec that are best
8// expressed as focused checks against the internal helpers.
9
10func TestInvariantAdminCannotConfiscate(cur realm, t *testing.T) {
11 reset()
12 doRegister(cur, "alice", alice, 100000)
13 n := getRaw("alice")
14
15 // invariant 18: admin has no routine power over an active user name.
16 errIs(t, authorize(admin, n, PermTransfer), errUnauthorized, "admin no transfer")
17 errIs(t, authorize(admin, n, PermManageRecords), errUnauthorized, "admin no records")
18
19 // invariant 14/17 via ReserveName: an actively-owned name cannot be reserved
20 // (confiscated). We assert the precondition the crossing path enforces.
21 isFalse(t, available("alice"), "active name unavailable to others")
22 isTrue(t, isActive(n) && n.Owner.IsValid(), "name active and owned")
23}
24
25func TestInvariantGraceNotRegisterable(cur realm, t *testing.T) {
26 reset()
27 doRegister(cur, "alice", alice, 1000)
28 testing.SkipHeights(210) // into grace
29 eqStr(t, string(StatusGrace), string(Status("alice")), "in grace")
30 // invariant 3: a grace-period name cannot be registered by another user.
31 isFalse(t, available("alice"), "grace name not available")
32}
33
34func TestInvariantSingleEffectiveOwner(cur realm, t *testing.T) {
35 reset()
36 doRegister(cur, "alice", alice, 100000)
37 // invariant 1: exactly one owner.
38 o1, ok := OwnerOf("alice")
39 isTrue(t, ok, "owned")
40 testing.SetRealm(testing.NewUserRealm(alice))
41 Transfer(cross(cur), "alice", bob, true, false)
42 o2, _ := OwnerOf("alice")
43 isFalse(t, o1 == o2, "owner changed to exactly one new owner")
44 eqStr(t, bob.String(), o2, "single new owner")
45}
46
47func TestInvariantPermanentOnlyRestrictive(t *testing.T) {
48 reset()
49 // invariant 5, exhaustive over all flags.
50 all := ControlPolicy{
51 OwnerCanTransfer: true, OwnerCanCreateSubnames: true, RecordsMutable: true,
52 ParentCanReclaim: true, ParentCanTransfer: true, ParentCanDelete: true,
53 ParentCanChangePolicy: true, Permanent: true,
54 }
55 // try to relax everything
56 got := mergeRestrictive(all, all) // identity keeps all true
57 isTrue(t, got.OwnerCanTransfer && got.RecordsMutable && got.ParentCanReclaim, "identity keeps flags")
58
59 none := ControlPolicy{Permanent: true}
60 restricted := mergeRestrictive(all, none)
61 isFalse(t, restricted.OwnerCanTransfer, "all restricted off")
62 isFalse(t, restricted.ParentCanReclaim, "reclaim off")
63 isTrue(t, restricted.Permanent, "permanent stays on")
64
65 // cannot turn any back on
66 reenable := mergeRestrictive(restricted, all)
67 isFalse(t, reenable.OwnerCanTransfer, "cannot re-enable transfer")
68 isFalse(t, reenable.RecordsMutable, "cannot re-enable records")
69}
70
71func TestInvariantPriceOverflowSafe(t *testing.T) {
72 reset()
73 config.BasePricePerSecond = 1 << 40
74 // invariant 10: overflow returns an error, never a wrapped value.
75 _, err := priceFor("a", 1<<40) // *100 multiplier -> overflow
76 isErr(t, err, "overflow detected")
77}
78
79func TestInvariantCommitmentTiming(cur realm, t *testing.T) {
80 reset()
81 commit, _ := MakeCommitment("alice", alice, 1000, "s", "", config.PolicyRevision)
82 testing.SetRealm(testing.NewUserRealm(alice))
83 Commit(cross(cur), commit)
84
85 cs := CommitmentStatus(commit)
86 // invariant 8: ready/expiry window is enforced by MinCommitAge/MaxCommitAge.
87 eqInt(t, cs.CreatedAt+config.MinCommitAge, cs.ReadyAt, "ready at min age")
88 eqInt(t, cs.CreatedAt+config.MaxCommitAge, cs.ExpiresAt, "expires at max age")
89}
90
91func TestPauseGatePure(t *testing.T) {
92 reset()
93 // paused reads still work; the mutation gate is requireNotPaused.
94 config.Paused = true
95 // Status is a read; must still function while paused.
96 eqStr(t, string(StatusAvailable), string(Status("nobody")), "reads work while paused")
97 config.Paused = false
98}
99
100func TestRecordLimitsConfigured(t *testing.T) {
101 reset()
102 // invariant 13: per-name storage bounds are configured and enforced.
103 isTrue(t, config.MaxRecordsPerName > 0, "record count bound configured")
104 isTrue(t, config.MaxTextValueBytes > 0, "text size bound configured")
105 isTrue(t, config.MaxOperatorsPerName > 0, "operator bound configured")
106}