1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-05-06 22:04:05 +00:00
Commit graph

181 commits

Author SHA1 Message Date
lukinovec
9ed7f1abf9
Merge d9ae27425d into 23b18c93a0 2026-05-05 10:06:56 +02:00
lukinovec
98a808bb98 Quote schema names in GRANT statements
PermissionControlledPostgreSQLDatabaseManager now uses the same quoting in GRANT statements as its schema counterpart.
2026-05-04 11:59:11 +02:00
lukinovec
405aaafb4e Handle MySQL charset and collation
Make createDatabase execute CREATE DATABASE without passing charset and collation so that if these parameters are null, the MySQL server's defaults will be used. Only add charset and collation to the statement if they're not null.
2026-05-04 11:15:51 +02:00
41701aff5f
phpstan fix: Model covariants in Scope generics
Builds on changes in recent commit:
Commit ID: c32f52ce7c
Change ID: qsnosyvyulxzrnzorpxqwqqztmqorsmk
2026-05-01 16:09:52 +02:00
lukinovec
ea20eb13b6 Validate in-memory DBs outside of isInMemory
isInMemory should check if the name looks ilke an in-memory database name and return bool (it shouldn't throw validation errors).

Also, make the validation methods non-static.
2026-05-01 15:22:40 +02:00
lukinovec
429e0985fd Improve code quality and comments 2026-05-01 15:17:38 +02:00
lukinovec
9a9adc0d99 Use getPath() in makeConnectionConfig()
makeConnectionConfig() would use database_path() to generate the DB path, which is correct only when the $path static property is null.
2026-05-01 14:27:56 +02:00
lukinovec
e48d822772 Validate SQLite DB name unconditionally in getPath() 2026-05-01 14:15:47 +02:00
github-actions[bot]
7683befa54 Fix code style (php-cs-fixer) 2026-05-01 12:10:13 +00:00
lukinovec
48b4837905 Validate in-memory db names, move SQLite-specific methods to the SQLiteManager 2026-05-01 14:09:56 +02:00
lukinovec
7363318f6e Make in-memory DB detection more strict
In-memory DBs have to start with "file:_tenancy_inmemory_". This prevents path traversal.
2026-05-01 13:09:37 +02:00
github-actions[bot]
fc6a931a32 Fix code style (php-cs-fixer) 2026-05-01 09:50:30 +00:00
lukinovec
1a01164b87 Make validateFilename accept string instead of ?string 2026-05-01 10:46:37 +02:00
lukinovec
2bdda23a56 Disallow empty strings as filenames 2026-05-01 10:37:22 +02:00
github-actions[bot]
f3836cc623 Fix code style (php-cs-fixer) 2026-05-01 07:34:32 +00:00
lukinovec
9611a05f35 Skip null parameters, throw for other non-string parameters 2026-05-01 09:34:11 +02:00
lukinovec
e8168eb0b9 Add string check to validateFilename, swap validation order
Validate characters first, only then throw if the filename is a directory.
2026-05-01 09:16:17 +02:00
lukinovec
d3607f84bf Use 'allowedCharacters' instead of 'allowlist', code quality 2026-05-01 09:11:55 +02:00
lukinovec
76c324d758 Add validateFilename()
Use validateFilename instead of validateParameter in SQLiteDatabaseManager. Directories are no longer considered valid SQLite database names.
2026-05-01 09:03:50 +02:00
lukinovec
2bd3a868ec Quote database parameter in GRANT statement for consistency
The database name is always quoted in statements (without binding) now.
2026-04-30 16:14:06 +02:00
lukinovec
37a4c7dd27 Check if paremeter is string 2026-04-30 15:08:46 +02:00
lukinovec
bacbf934e1 Improve validation exception message 2026-04-30 14:52:53 +02:00
lukinovec
46f73c42ad Improve ValidatesDatabaseParameters comments, delete extra early return 2026-04-30 10:44:36 +02:00
lukinovec
322257f456 Validate SQLite filename in databaseExists
Add validation so that a malicious tenant DB name can't be used to detect if a file exists.
2026-04-30 09:49:03 +02:00
lukinovec
75b74f2e6c Make validateParameter have void return type 2026-04-30 09:28:48 +02:00
lukinovec
f3f1ab977a
Skip null parameters in validateParameter
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-04-30 09:15:18 +02:00
lukinovec
85929493d5 Improve ValidatesDatabaseParameters docblocks 2026-04-29 17:35:11 +02:00
lukinovec
740d53e9cc Rename ValidatesSqlParameters to ValidatesDatabaseParameters 2026-04-29 17:35:11 +02:00
lukinovec
0fdb8b2041 Validate user passwords in DB managers
Also, make the validateParameter method ignore null parameters, e.g. for cases when tenants are created using Tenant::make() without tenancy_db_username set -- $databaseConfig->getUsername() allows null, same should go for the validate method whose only concern is checking strings for invalid characters.
2026-04-29 17:35:11 +02:00
lukinovec
db03997339 Validate SQLite DB names in create/deleteDatabase()
Also stop skipping the validation test for sqlite.
2026-04-29 17:35:11 +02:00
lukinovec
d5087d19c5 Extract parameter validation into a trait
Also, use parameterAllowlist() instead of the static property (so that we can e.g. override it later in SQLiteDatabaseManager, since overriding the static property doesn't work).
2026-04-29 17:35:11 +02:00
github-actions[bot]
182f3a2eb2 Fix code style (php-cs-fixer) 2026-04-29 12:16:22 +00:00
lukinovec
bdf592c0ff Add parameter validation to DB managers
DB manager methods validate the parameters they use in SQL statements using validateParameter() (excluding parameters passed via bindings in SELECT statements).
2026-04-29 14:13:56 +02:00
lukinovec
ad7d229daf Use parameter binding in SELECT queries 2026-04-29 10:21:47 +02:00
lukinovec
808f52765c Use select() instead of selectOne() in databaseExists() and userExists()
This is just for consistency, since all the other DB managers use select().
2026-04-29 10:08:45 +02:00
lukinovec
ab2a4d8438
Fix chaining withoutPending() with where() (#1457)
At the moment, `where()` cannot be used correctly while using
`withoutPending()`. For example, if we have a single non-pending tenant
in our DB (with ID 'foo'), queries like
`Tenant::withoutPending()->where('id', 'nonexistent')->first()`will
incorrectly return the non-pending tenant ('foo').

This is because `withoutPending()` does
`$builder->whereNull('data->pending_since')->orWhereNull('data')`. These
two aren't grouped, so `withoutPending()->where('id', 'nonexistent')`
basically translates to "WHERE data->pending_since IS NULL **OR (data IS
NULL AND id = 'nonexistent')**". So the query will include all tenants
whose `pending_since` is null (= all non-pending tenants).

Grouping `->whereNull('data->pending_since')->orWhereNull('data')` in a
closure passed to a separate `where()` fixes this issue.
2026-04-22 14:32:53 +02:00
c32f52ce7c
phpstan fix: Scope generics
phpstan started failing with '... implements generic interface
Illuminate\Database\Eloquent\Scope but does not specify its types:
TModel'. We solve this by adding an implements docblock to the scopes
implementing that interface. They're fairly generic - we just use the
Model type itself in the code - so we use Model for the type parameter.
2026-04-15 11:23:12 +02:00
c4960b76cb
[4.x] Laravel 13 support (#1443)
- Update ci.yml and composer.json
- Wrap single database tenancy trait scopes in whenBooted()
- Update SessionSeparationTest to use laravel-cache- prefix in L13
  and laravel_cache_ in <=L12. Our own prefix remains tenant_%tenant%_
  (as configured in tenancy.cache.prefix). We could update this to be
  tenant-%tenant%- from now on for consistency with Laravel's prefixes
  (changed in https://github.com/laravel/framework/pull/56172) but I'm
  not sure yet. _ seems to read a bit better but perhaps consistency
  is more important. We may change this later and it can be adjusted
  in userland easily (since it's just a config option).
2026-03-18 19:17:28 +01:00
Punyapal Shah
e3701f1cc1
[4.x] Add more relation type annotations (#1424)
This pull request adds improved PHPDoc type annotations to several
Eloquent relationship methods, enhancing static analysis and developer
experience. These changes clarify the expected return types for
relationships, making the codebase easier to understand and work with.

Relationship method type annotations:

* Added a detailed return type annotation to the `tenant` method in the
`BelongsToTenant` trait, specifying the related model and the current
class.
* Added a detailed return type annotation to the `domains` method in the
`HasDomains` trait, specifying the related model and the current class.
* Added a detailed return type annotation to the `tenants` method in the
`ResourceSyncing` class, specifying the related model and the current
class.
2025-12-28 23:20:05 +01:00
d274d8c902
pending tenants: minor cleanup 2025-10-29 22:54:53 +01:00
6523f24a60 Pending tenants: Add getPendingAttributes()
This method lets the user specify default values for custom
non-nullable columns. The primary use case is when the tenants table
has a column like 'slug' and createPending() is called with no
value for 'slug'. This would produce an exception due to the column
having no default value.

Here, getPendingAttributes() can set an initial dummy slug (like a
randomly generated string) before it's overwritten during a pull.

getPendingAttributes() accepts an $attributes array which corresponds
to the attributes passed to createPending(). The array returned from
getPendingAttributes() is ultimately merged with $attributes, so
the user doesn't need to use the $attributes value in
getPendingAttributes(), however it serves to provide more context when
the pending attributes might be dependent on $attributes and therefore
derived from the $attributes actually being used.

Also fixed the `finally` branch in createPending() as it was
potentially referencing the $tenant variable before it was initialized.
2025-10-28 12:50:13 +01:00
aba7a50619
Minor fixes
The change in SQLiteDatabaseManager wasn't properly saving the
updated internal value.

The check in CacheTenancyBootstrapper wasn't handling that local tests
have a 'testing' environment, not local. However fixing only the
condition would've still added the store to $names which would throw
an exception down the line. We make sure to only throw the exception
in prod, but also make sure to only add the store to $names if it is
supported.
2025-10-22 12:58:45 +02:00
99b79a5d08
SQLite DB manager: use setInternal() instead of hardcoded tenancy_db_* 2025-10-20 02:16:31 +02:00
a0a9b85982 Refactor DatabaseConfig, minor DB manager improvements, resolve todos
Notable changes:
- CreateUserWithRLSPolicies: Clarify why we're creating a custom
  DatabaseConfing instance
- HasDatabase: Clarify why we're ignoring tenancy_db_connection
- DatabaseConfig: General refactor, clarify the role of the host conn
- SQLiteDatabaseManager: Handle trailing DIRECTORY_SEPARATOR
  in static::$path
- DisallowSqliteAttach: Don't throw any exceptions, just silently fail
  since the class isn't 100% portable
- Clean up todos that are no longer relevant
- Clean up dead code or comments in some database managers
2025-10-13 16:01:34 +02:00
github-actions[bot]
364637dc23 Fix code style (php-cs-fixer) 2025-09-01 14:14:34 +00:00
13a2209f11 SQLite improvements
- (BC BREAK) Remove $WAL static property. We instead just let
  Laravel use its journal_mode config now
- Remove journal, wal, and shm files when deleting tenant DB
- Check that the system is 64-bit when using NoAttach (we don't
  build 32 bit extensions)
- Use local static instead of a class static property for caching
  loadExtensionSupported
2025-09-01 16:13:09 +02:00
4578c9ed7d Features refactor
Features are now *always* bootstrapped, even if Tenancy is not resolved
from the container.

Previous implementations include
https://github.com/tenancy-for-laravel/v4/pull/19
https://github.com/archtechx/tenancy/pull/1021

Bug originally reported here
https://github.com/archtechx/tenancy/issues/949

This implementation is much simpler, we do not distinguish between
features that should be "always bootstrapped" and features that should
only be bootstrapped after Tenancy is resolved. All features should work
without issues if they're bootstrapped when TSP::boot() is called. We
also add a Tenancy::bootstrapFeatures() method that can be used to
bootstrap any features dynamically added at runtime that weren't
bootstrapped in TSP::boot(). The function keeps track of which features
were already bootstrapped so it doesn't bootstrap them again.

The only potentialy risky thing in this implementation is that we're now
resolving Tenancy in TSP::boot() (previously Tenancy was not being
resolved) but that shouldn't be causing any issues.
2025-08-31 23:18:44 +02:00
33e4a8e4e2 Remove and recategorize todos 2025-08-31 16:57:52 +02:00
6b0066c5ef Pending tenants refactor (BC break)
- [BC BREAK] Make pullPendingFromPool() $firstOrCreate arg
  default to false (pullPending() is now a direct alias for
  pullPendingFromPool() with default $firstOrCreate=true)
- Resolve race conditions in pullPendingFromPool()
- Make createPending() set pending_since regardless of exceptions
- Make pullPending() accept $attributes
- Fire PullingPendingTenant from within a DB transaction
- Clarify --count arg description for CreatePendingTenants command
- Add docblock to PullingPendingTenant with a notice
2025-08-25 00:01:02 +02:00
8f8af34c32
[4.x] Only revert initialized bootstrappers (#1385)
* Only revert initialized bootstrappers (Tenancy::initializedBootstrappers)

* Fix use of @property across the codebase
2025-08-05 11:12:25 +02:00