mirror of
https://github.com/go-admin-team/go-admin.git
synced 2026-09-25 19:36:07 +00:00
sys_app_casbin_grant has existed since the registry tables were added and nothing ever wrote to it. An uninstaller reading it would have found it empty, deleted no policy at all, and reported every one of them as an unattributable leftover - which is what "report and skip" looks like when the ledger was simply never written, and is indistinguishable from it working. grantToAdminRole now writes an entry for each policy it creates. The entry carries the tuple casbin_rule is unique on rather than a foreign key into it, because casbin_rule is not this project's table: the gorm adapter's SavePolicy truncates it and writes it back from memory, and SysRole.Update replaces a role's policy rows wholesale. Both rebuild the same tuple from the same sys_menu/sys_api data, so a match on the tuple survives what a row id does not. Only policies this install actually created are recorded - the insert is conditional and its RowsAffected says which. A policy that was already there was granted by somebody else and is not this app's to take away. The two ways that can be wrong are not equally bad, which is what settles it. Under-recording leaves a policy behind and the uninstall says so, because a policy naming this app's own path with no ledger entry is exactly what it reports as an orphan. Over-recording deletes somebody's authorization, silently. Between a visible leftover and an invisible deletion, take the leftover. The ledger insert is itself conditional, for a case the obvious retry test does not reach: on a plain re-run the policy still exists, so the insert is skipped before the ledger is touched. It is reached when the policy row was removed while its entry stayed, and a plain insert would then abort the whole seed on the ledger's unique index. There is a test for that specific shape, and replacing the insert with a plain one turns it red - which the plain retry test does not. Ordering: the ledger table is created by a framework migration, and version strings sort bare digits ahead of any app-prefixed one, so it exists before any application's seed runs. Nothing in the framework's own migrations calls SeedMenus.