Cosmic Bull

Realm on pearl-1

permission_registry

gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/permission_registry

realmpipeline-applicationaccess-control

RenderedSourceCall builderState

curated

Global named-permission registry with admin-scoped resources. GitHub-pipeline application #4.

Identity

Import pathgno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/permission_registry
Kindrealm (/r/)
Chainpearl-1
Namespaceg1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3
Realm addressg1x9tatmqcdlas2w6k724mrs2zcgh3awf3s5wkhk derived, never confirmed against the realm

Provenance

chain-attested
Deployed at height604,615
Deploy transactiona30c09427173a45553a9befcac38d410aa0e416eb785145942ee5378d6a8c54f look it up on the RPC
Deployerg1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3
Gas used29,251,583
Storage24,721 bytes, deposit 2472100ugnot
Files on chaingnomod.toml permission_registry.gno
Deployed bytespermission_registry.gno — 18,070 bytes
sha256603fec571a55d051353e101c64c0490a5268124abda8d88ac703b9bbf26fb763

Do not take the hash above on trust. $download returns the bytes pearl-1 is actually running; this command fetches them and prints their digest, which should equal the one in the table:

curl -sS 'https://pearl.testnets.gno.land/r/g1ut6uspuh73e02yauxpmyt8g3wwddaq8utagvm3/permission_registry$download&file=permission_registry.gno' | shasum -a 256

Expected: 603fec571a55d051353e101c64c0490a5268124abda8d88ac703b9bbf26fb763 — 18,070 bytes. This was checked for all 21 packages while building this site's architecture record; every one matched. Use curl: pearl's edge answers Python's default user-agent with HTTP 403.

API

chain-derived 13 exported functions, 1 type.

Every function below deep-links to gnoweb's call builder, which generates a ready-to-run gnokey maketx call for it:

AcceptAdminCancelAdminTransferCreateResourceDeleteResourceGetAdminGetPendingAdminGetPermissionsGrantHasListResourcesRenderRevokeTransferAdmin

Overview

This package carries no package doc comment on chain, so there is nothing for vm/qdoc to return and gnoweb's $help Overview is empty. Deployed bytes are immutable, so this cannot be repaired in place — see catalog/DISCOVERY_APIDOCS.md §2.4.

Imports

Constants and variables

const (
	// MaxResources bounds total registry state. Raised from the upstream
	// 200 as part of the R1 remediation: with a per-admin quota now
	// carrying the anti-monopoly duty, the global cap is a pure state
	// bound rather than the sole defense against namespace exhaustion.
	MaxResources = 1000

	// MaxResourcesPerAdmin bounds how many resources one address may hold
	// at once. R1 (audit 2026-09-21): the upstream design had only a
	// global cap on a permissionless shared registry, so one unprivileged
	// key could occupy every slot for ~200 cheap transactions and
	// permanently deny the registry to every other tenant. DeleteResource
	// is admin-only, so the squat was irreversible.
	MaxResourcesPerAdmin = 20

	MaxPermissionsPerResource = 50
	MaxHoldersPerPermission   = 200
	MaxNameLen                = 64

	// ReservationPeriod is how long a deleted resource name stays
	// reserved. Finite (re-audit 2026-09-02): eternal tombstones let an
	// attacker cycle create/delete to lock the namespace forever.
	ReservationPeriod = int64(90 * 24 * 3600) // 90 days

	// Render bounds (Y3, audit 2026-09-21). Render walks the whole
	// registry and is reachable by any viewer through gnoweb and
	// vm/qrender, so its cost is borne by third parties rather than by
	// whoever grew the state. Uncapped, the declared limits allowed
	// 1000*50*200 rendered holder entries. The full data stays available
	// through ListResources / GetPermissions / Has, which are bounded per
	// call by construction.
	MaxRenderResources   = 20
	MaxRenderPermissions = 8
	MaxRenderHolders     = 10
)

Types

type Reservation

type Reservation struct {
	Admin   address
	Creator address
	Expires time.Time
}

Reservation holds a deleted resource name for its former admin AND its original creator, and expires.

Functions

AcceptAdmin

func AcceptAdmin(cur realm, resourceName string)

Crossing function. Callable from a transaction via MsgCall, and from another realm as AcceptAdmin(cross(cur), ...).

AcceptAdmin completes a pending handoff; only the nominee may call it. The nominee's quota is checked HERE — at consent time — so a nomination can never push an account past MaxResourcesPerAdmin without that account agreeing to carry the resource.

CancelAdminTransfer

func CancelAdminTransfer(cur realm, resourceName string)

Crossing function. Callable from a transaction via MsgCall, and from another realm as CancelAdminTransfer(cross(cur), ...).

CancelAdminTransfer withdraws a pending nomination. Only the current admin can call this.

CreateResource

func CreateResource(cur realm, resourceName string)

Crossing function. Callable from a transaction via MsgCall, and from another realm as CreateResource(cross(cur), ...).

CreateResource registers a new named resource. The caller becomes its admin and is the only address that can grant or revoke permissions on it. A deleted resource name stays reserved for its former admin and its original creator until the reservation expires.

Each address may administer at most MaxResourcesPerAdmin resources at once, and the registry holds at most MaxResources in total.

DeleteResource

func DeleteResource(cur realm, resourceName string)

Crossing function. Callable from a transaction via MsgCall, and from another realm as DeleteResource(cross(cur), ...).

DeleteResource removes a resource and every permission under it. Only the resource admin can call this. The name stays reserved for the caller and for the original creator: nobody else can re-create it and inherit its consumers until the reservation expires.

GetAdmin

func GetAdmin(resourceName string) string

GetAdmin returns the admin address of a resource.

GetPendingAdmin

func GetPendingAdmin(resourceName string) string

GetPendingAdmin returns the nominated admin awaiting acceptance for a resource, or "none".

GetPermissions

func GetPermissions(resourceName string, addr address) string

GetPermissions returns all permission names granted to addr on a resource, as a comma-separated string. Returns "none" if the address has no permissions.

Grant

func Grant(cur realm, resourceName, permission string, addr address)

Crossing function. Callable from a transaction via MsgCall, and from another realm as Grant(cross(cur), ...).

Grant gives an address a named permission on a resource. Only the resource admin can call this. Panics if the permission is already granted to avoid silent no-ops.

Has

func Has(resourceName, permission string, addr address) bool

Has returns true if addr holds the named permission on the resource. Returns false (never panics) for unknown resources or permissions.

INTEGRATOR CONTRACT (Y7): Has takes the subject address explicitly and performs NO caller authentication — it answers "does this address hold this permission", not "may my caller do this". A consuming realm must derive addr from its own crossing entrypoint's cur.Previous().Address() and pass it in. Deriving it inside a non-crossing helper via unsafe.PreviousRealm() resolves the consumer's own caller's caller and is a Class-2 designation-forgery bug in the consumer.

ListResources

func ListResources() string

ListResources returns all registered resource names as a comma-separated string in registration order. Returns "none" if no resources exist.

Render

func Render(path string) string

Render returns a markdown overview. Never panics. Output is bounded by MaxRenderResources / MaxRenderPermissions / MaxRenderHolders (Y3); truncated sections name the query to use for complete data.

Revoke

func Revoke(cur realm, resourceName, permission string, addr address)

Crossing function. Callable from a transaction via MsgCall, and from another realm as Revoke(cross(cur), ...).

Revoke removes a permission from an address. Only the resource admin can call this. Panics if the permission was not granted. A permission left with no holders is pruned from the resource's permission list.

TransferAdmin

func TransferAdmin(cur realm, resourceName string, newAdmin address)

Crossing function. Callable from a transaction via MsgCall, and from another realm as TransferAdmin(cross(cur), ...).

TransferAdmin nominates a new admin for a resource. Only the current admin can call this, and the handoff does NOT take effect until the nominee calls AcceptAdmin.

Y4 (audit 2026-09-21): the upstream one-step transfer made a well-formed-but-unowned destination permanently fatal. address.IsValid only checks bech32 form, so a mistyped address passed the check and left the resource with an admin nobody controls — it could never again be granted on, revoked from, transferred or deleted, and its slot was lost from both the global cap and the former admin's quota forever. Nomination is reversible; only the nominee's consent is final.


Doc text is reproduced as vm/qdoc returns it. The node markdown-escapes doc comments, so a bracket or angle bracket may carry a backslash the committed source does not have. The source itself is at source and in this repository.

Dependencies

chain-attested
Importschain/runtime/unsafe, sort, strconv, strings, time
First-party dependenciesnone
Used bynone

Known limitations

Recorded by the people who built and deployed it. This list is deliberately not empty where honesty costs something.

curated

Source and records

Source filepearl/r/permission_registry/permission_registry.gno at commit 6a510c665a53 in the project repository (not public — the digest command above is the check that needs no repository)
Matches the deployed bytesyes — byte-identical
Upstream repositoryhttps://github.com/SillyZir/permission_registry
Deployed from commite3d6aeaf3571ec35c2af68c5fbb756480b76ed03
Recordscatalog/applications.md#permission_registry
pearl/DEPLOYMENT.md