fastfony/license-bundle
A Laravel bundle for adding license key management to your app, with tools to generate, assign, validate, and track licenses and activations so you can control access, handle expirations, and manage renewals in PHP projects.
Before anything else, two facts shape how you'll use this package: it is a Symfony bundle, and it is archived. That means (a) there is no Laravel auto-discovery, and (b) there will be no upstream fixes — you are evaluating it as source code you may vendor, fork, or cannibalise rather than as a dependency you can trust to track upstream.
Minimal steps:
composer.json first — it tells you the supported Symfony versions, the PHP floor, and whether it pulls in the Packagist API client or any HTTP dependency. An archived package with a stale Symfony constraint is the single most common reason it won't install on a modern app.src/DependencyInjection/Configuration.php (or equivalent) — this is the authoritative config tree. Treat the README as illustrative and the config tree as truth.src/Command/ — the whole package is usually one or two console commands. That's your real API surface.First use case, and the one that justifies the package at all: a CI gate. Run the check command against composer.lock, allowlist the licenses your legal/OSS policy permits (MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC), and let a non-zero exit code fail the build. Everything else — HTML reports, dashboards, per-package overrides — is secondary.
If you are on Laravel and want a same-day result, the honest first move is to run the bundle's command logic as a standalone script (or copy the checker class into app/Support/) rather than fighting Symfony bundle registration. The value is the license-resolution logic, not the bundle wiring.
CI gate with an allowlist. The core pattern: allowlist in config, composer.lock as input, exit code as output. Keep the allowlist in version control next to the code so a reviewer sees license-policy changes in the diff, not buried in CI variables.
Denylist for the risky tail. Most teams find it easier to enumerate what's forbidden (AGPL-3.0, GPL-3.0, SSPL-1.0, proprietary, unknown) than to enumerate everything permitted. Unknown/empty license strings are the case that actually bites, so make sure your config treats "no license declared" as a failure, not a pass.
Baseline / ignore list. You will have transitive dependencies you cannot replace (a dev tool, a transitive adapter). Support an explicit, commented ignore list keyed by name@version so it fails loudly when the version changes — a bare name ignore silently hides a license change on upgrade.
Wire it into Composer, not just CI. A post-install-cmd/post-update-cmd script surfaces a newly-introduced GPL dependency at the moment someone adds it, in their own terminal, instead of twenty minutes into a pipeline. Developers actually change behaviour when the feedback is local.
Artifact the report. Even if the gate is the point, emit a machine-readable report (JSON) as a build artifact. It's what you hand to legal, and it's what lets you diff licenses across releases to answer "when did this GPL package appear?"
Laravel integration, if you go that route. Wrap the check in an Artisan command and register it in app/Console/Kernel.php; bind the checker as a singleton in a service provider. Keep the command thin — argument parsing and exit code only — and let the checker class stay framework-free so it's testable without booting the app. If you can't get the bundle's container wiring to cooperate, this is the cheaper path.
Scheduled drift check. Licenses can change between releases of the same package. A weekly scheduled job that re-resolves licenses from the lock file catches a maintainer re-licensing a dependency, which is a real and underrated supply-chain risk.
Archived means fork-and-own. No security patches, no PHP 8.x compatibility fixes, no new-license coverage. Pin it exactly, or copy the handful of classes you need into your codebase with the MIT header intact. The latter is usually the right call for something this small — you get the logic without the dead dependency.
Symfony/Laravel mismatch. No package discovery, no config/*.php merge, no vendor:publish. You'll be hand-registering services and hand-loading YAML (or converting the config tree to a PHP array). Budget for this; it's the main reason Laravel developers bounce off Symfony bundles.
License data is only as good as composer.lock. The license field is frequently empty, occasionally a string array of alternatives, and sometimes contradictory with the package's actual LICENSE file. A checker that reads only the lock file will report unknown for exactly the packages you most want to know about. Look for whether the package falls back to reading vendor/*/*/LICENSE, and if it doesn't, add that yourself.
OR/AND semantics. Multi-license strings mean different things: MIT OR GPL-2.0 is fine (you pick MIT), MIT AND GPL-2.0 is not. Naive string matching gets this wrong in both directions. Verify how the package splits license expressions before you trust a green build.
Dev dependencies matter less, but not zero. require-dev packages don't ship to production, but they do run in your CI and can carry obligations. Decide explicitly whether to include them, and make that a config flag rather than an accident of which command variant you call.
Silent passes. The classic failure mode: the checker can't resolve something, logs a warning, and exits 0. Test this deliberately — add a fake package with no license and confirm the build goes red. An archived package is unlikely to have had that path hardened.
Network dependencies. If the checker calls Packagist to resolve licenses, your build now depends on an external API. Prefer lock-file-only resolution, or at minimum cache the response in CI; a rate-limited Packagist should not be able to fail your release.
Extension points worth finding. Look for an interface on the license-resolution step (so you can plug in a local SPDX dataset) and on the report formatter (so you can emit SARIF and get inline annotations in pull requests). Those two seams cover most real-world customisation; anything else, fork.
Debugging. The output you'll want when it says a package is disallowed is which license string was matched against which rule. If the command doesn't do that, add it early — otherwise you'll be grepping composer.lock by hand for every CI failure, and people will start ignoring the build.
Alternatives worth considering before adopting. For a straightforward "is anything copyleft in here" check, composer-license-check or a ~40-line script over composer.lock gets you 90% of the value with none of the abandoned-bundle risk. Adopt this one only if you specifically want its config model or report shape — and be prepared to maintain it.
How can I help you explore Laravel packages today?