A kijelölt tartományból elkészül a feltölthető mappa: deploy_<target>_<időbélyeg>, benne a fájlok eredeti relatív útvonalon, hogy a feltöltés mappa-összeolvasztás legyen. - GitRepository::archiveTo(): git archive --format=zip + ZipArchive kicsomagolás, ~100 fájlonként darabolva a parancssor-limit miatt. A tartalom a git objektumtárból jön, nem a working tree-ből: így nem szivárog ki commitolatlan módosítás, és a .gitattributes eol=lf miatt LF sorvéggel kerül a Linux célgépre. Üres pathspec esetén nem hívunk gitet, mert az a TELJES fát csomagolná. - DeploymentPackageBuilder: _MANIFEST.json/.txt (sha1 + méret fájlonként), _TORLENDO.txt a törölt és az átnevezett fájlok régi útvonalával, _TEENDOK.md a diffből származó lépésekkel (migrate, composer install, asset-figyelmeztetés, verzió-ellenőrzés), és public/ deploy-version.json a kirakott commit hashével. - A git archive által kihagyott fájlok (pl. .gitattributes export-ignore) külön "missing" listára kerülnek - csendben hiányzó fájl a manuális deploynál a legrosszabb hiba. - Felületen fájlonkénti kézi kivétel, megerősítéses csomagolás gomb, eredmény-kártya. - DeploymentGuard::ensureEnvironmentAllowed(): a builder felhasználó nélkül is ellenőrzi az env kapcsolót és a stage whitelistet, így konzolról indítva sem fut le egy szerveren. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
93 lines
3.0 KiB
PHP
93 lines
3.0 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Deployment;
|
|
|
|
use App\Models\User;
|
|
use Laravel\Pennant\Feature;
|
|
use RuntimeException;
|
|
|
|
/**
|
|
* A deployment csomagoló hozzáférés-ellenőrzése egy helyen.
|
|
*
|
|
* Az alkalmazás kódja manuális fájlmásolással kerül a szerverekre, tehát ez az oldal
|
|
* fizikailag ott lesz az éles környezetben is. Ezért négy, egymástól független feltétel
|
|
* van, és mindet MINDEN belépési ponton ellenőrizni kell (oldal mount, akciók, később a
|
|
* csomagoló service) - ha csak a felületet védjük, az látszatvédelem.
|
|
*
|
|
* A négyből a tényleges védelmet az .env kapcsoló és a stage whitelist adja, a
|
|
* jogosultságot a szerepkör. A feature flag NEM biztonsági réteg: a menü-láthatóságot
|
|
* vezérli, és lehetővé teszi a deploy nélküli kikapcsolást, illetve a név szerinti
|
|
* átadást (feature_flag_overrides) developer szerep osztogatása nélkül.
|
|
*/
|
|
class DeploymentGuard
|
|
{
|
|
public function isAllowed(?User $user = null): bool
|
|
{
|
|
return $this->denialReason($user) === null;
|
|
}
|
|
|
|
/**
|
|
* Csak a környezeti feltételek (1-2. réteg), felhasználó nélkül.
|
|
*
|
|
* Ezt hívja a csomagoló service is: így akkor sem fut le, ha valaki a felületet
|
|
* megkerülve (konzolról, jobból) indítaná el egy szerveren.
|
|
*/
|
|
public function environmentDenialReason(): ?string
|
|
{
|
|
if (! config('deployment.enabled')) {
|
|
return 'A deployment csomagoló ki van kapcsolva (DEPLOYMENT_PACKAGE_ENABLED).';
|
|
}
|
|
|
|
/** @var array<int, string> $stages */
|
|
$stages = (array) config('deployment.stages', []);
|
|
|
|
if (! in_array((string) config('app.stage'), $stages, true)) {
|
|
return sprintf(
|
|
'A deployment csomagoló csak fejlesztői környezetben használható (engedélyezett stage: %s, jelenlegi: %s).',
|
|
implode(', ', $stages),
|
|
(string) config('app.stage'),
|
|
);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Az első nem teljesülő feltétel magyarázata, vagy null, ha minden rendben.
|
|
*/
|
|
public function denialReason(?User $user = null): ?string
|
|
{
|
|
if ($reason = $this->environmentDenialReason()) {
|
|
return $reason;
|
|
}
|
|
|
|
if (! $user) {
|
|
return 'Bejelentkezés szükséges.';
|
|
}
|
|
|
|
if (! $user->hasRole((string) config('deployment.role'))) {
|
|
return 'A deployment csomagoló csak fejlesztői szerepkörrel érhető el.';
|
|
}
|
|
|
|
if (! Feature::for($user)->active((string) config('deployment.feature_flag'))) {
|
|
return 'A deployment csomagoló feature flag nincs bekapcsolva erre a felhasználóra.';
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function ensureAllowed(?User $user = null): void
|
|
{
|
|
if ($reason = $this->denialReason($user)) {
|
|
abort(403, $reason);
|
|
}
|
|
}
|
|
|
|
public function ensureEnvironmentAllowed(): void
|
|
{
|
|
if ($reason = $this->environmentDenialReason()) {
|
|
throw new RuntimeException($reason);
|
|
}
|
|
}
|
|
}
|