andika/tameng
Tameng is a Laravel package that adds a lightweight security shield to your application, helping guard routes and requests from common threats with simple configuration. It integrates cleanly with middleware and is easy to enable in existing Laravel projects.
Tameng is a Filament panel authorization package (roles, permissions, and policies) driven almost entirely by Artisan commands. Start with the installer, not the docs:
composer require --dev ? # see package docs for the correct constraint
php artisan tameng:install
tameng:install publishes config/migrations and prints the next steps — including the suggested tameng:super-admin invocation. In 1.4.0 that suggestion was corrected to match the command's actual interactive/flag usage, so copy it verbatim rather than guessing flags.
Then generate the permission catalogue:
php artisan tameng:generate
As of 1.4.0 the permission counter no longer accumulates incorrectly: totals now include resources and pages, widgets, and custom permissions. The printed counts during generation are therefore trustworthy for the first time — use them as a sanity check that your panels are being discovered.
First use case: pick one Resource, run tameng:generate, assign the resulting permission to a role via your admin panel, and confirm a non-super-admin user is blocked. Look first at:
scoped_to_panel if you run multiple panels.PermissionHelper — it is the single source of truth for permission naming and labelling, and it is where most behavior is decided.Keep the plugin registered per panel. TamengPlugin is the integration point; register it in each panel provider that should be covered. Panel scoping is configured through scoped_to_panel, and 1.4.0 makes that setting actually honored end-to-end (PermissionHelper::permissionName(), permissionLabel(), EnsurePagePermission, HasPermissionCheck, and tameng:check).
Use tameng:sync as your deploy step, not generate. The 1.4.0 overhaul means sync now reconciles pages, widgets, custom permissions, and role policies alongside resources — previously it only handled resources, leaving drift. A typical CI/deploy flow:
php artisan tameng:sync # reconcile catalogue + policies
php artisan tameng:check # verify, now panel- and guard-aware
Let sync own your policies. Generated policies now carry before/after lifecycle hooks. The before hook is the idiomatic place for super-admin / ownership overrides instead of hand-editing every policy method; after is where you return null to fall through or a bool to hard-override. Because sync rewrites these files, put custom logic in the hooks (or in a base policy you extend) rather than in generated method bodies, which you will lose on the next sync.
Guard your UI, don't just hide buttons. EnsurePagePermission middleware protects page routes; HasPermissionCheck gives you in-page checks. Rely on both — Filament's navigation hiding is cosmetic, and direct URL access to a page is exactly what the middleware exists to stop.
Panel-scoped naming for multi-panel apps. When scoped_to_panel is enabled, permission names are prefixed with the panel ID. Write your own checks through PermissionHelper::permissionName() rather than string-concatenating names, so your code follows whatever scoping the config dictates.
Custom permissions for non-resource abilities. Anything not backed by a Resource/Page/Widget (e.g. "export reports", "approve refunds") should be declared as a custom permission so it lands in the catalogue with correct totals and is picked up by sync and check.
scoped_to_panel enabled may have permission names generated without the panel prefix. After upgrading to 1.4.0, run tameng:sync then tameng:check in a non-production environment first: the names changing means existing role assignments can silently stop matching.tameng:check is now scope-aware — treat new failures as real. If check reports missing permissions post-upgrade, it is usually correct: those permissions genuinely were not being enforced before.permissionLabel() for display, so card labels read cleanly while the underlying name keeps the prefix. If you build custom permission UIs, use permissionLabel() for display and permissionName() for storage/comparison — never mix them.before/after hooks; tameng:sync will overwrite them.PermissionHelper::permissionName()), then the guard, then the panel scope. In multi-panel setups a mismatch in any of the three looks identical from the UI — a 403 with no explanation.before hook, so a super admin will never reproduce a permission bug. Always test denials as a scoped, non-super-admin user.PermissionHelper, TamengPlugin, HasPermissionCheck, and EnsurePagePermission — read those tests rather than the docs when you need to know exact semantics of panel scoping or label stripping, and mirror their setup in your own feature tests.How can I help you explore Laravel packages today?