The codebase lock — nightly ownership management
BOA treats code ownership on tenant platforms as managed state. Once per night, the maintenance worker walks every registered site, resolves its platform root, and re-asserts both ownership and permissions. The historical motivation (post-Drupalgeddon) was to make sure a compromised site or a leaked SFTP credential cannot quietly rewrite code or strip the hardening; the mechanism survives today as the default lock, with a tenant-controlled unlock for in-place maintenance.
What the nightly pass does
For each registered site's platform (per account, once per night per
platform, tracked by marker files under ~/log/ctrl/):
- Platforms under
~/static(all tenant platforms live there): the whole codebase is chowned to the account's backend user (oN). For composer-managed shapes (a docroot withcore/lib/Drupal.phpnext to../vendor/autoload.phpand acomposer.jsonrequiringdrupal/core) the pass operates on the repository root, sovendor/andcomposer.jsonare covered too. Then the permission sweep: directories0775, files0664, and the hardened read-only paths (vendor/drush, selectedvendor/symfony/consoleinternals) locked to0400. - Platform level (every registered platform, in addition to the pass
above):
sites/all/{modules,themes,libraries}/*chowned tooN:users; thesites/skeleton re-asserted (sites0751,sites/*0755,sites/*.php0644); stray code archives (*.tar,*.tar.gz,*.zip) insidesites/alltrees are deleted. - Site level: each site's
{modules,themes,libraries}/*chowned tooN:userswith directories02775and files0664; settings-class files (settings.php,local.settings.php,civicrm.settings.php) kept atoN:www-data, mode0440/0640; the site'sfiles/tree chowned tooN:www-data(symlink-safe,chown -h).
Group-write for the shell pair survives all of this — the lock manages
the ownership axis, and with it the owner-only rights: chmod, git's
repository-ownership trust, and replacing read-only paths. The web
identity (the per-account .web FPM user, a member of www-data only)
can write code in neither state.
The two tenant switches
~/static/control/unlock.info— account-wide direction flip. While it exists, the code-tree chowns above targetoN.ftpinstead ofoN— the whole tree for~/staticplatforms, and the{modules,themes,libraries}contents at platform and site level; the container directories, settings files andfiles/areas stay with the backend user. That hands the owner-only rights to the shell account so in-placecomposer updateand git work function. Takes effect on the next nightly run; removing the file re-locks the next night. The tenant-facing workflow is documented in the Using tree (in-place upgrades).<platform root>/skip.info— per-platform opt-out from the recursive code-tree chowns in both directions: a skipped platform keeps whatever ownership you set on the code trees. The container directories, settings files andfiles//private/areas are still re-chowned to their managed owners, and the permission sweep still runs. The whole-tree pass on composer shapes checks the repository root forskip.info; thesites/alland site-level passes check the docroot — advise tenants to place it in both for composer-managed codebases.
Platforms that carry no registered site are never visited by the nightly pass at all — their ownership and permissions are entirely manual (see shared codebase permissions for the group-write repair tool for such trees).
Operator knobs
_PERMISSIONS_FIX=YESin/root/.barracuda.cnf(defaultYES) gates the entire nightly permission/ownership machinery./etc/boa/.dont.touch.permissions.cnf— box-wide kill file; its presence skips the machinery for every platform, overriding everything below.fix_files_permissions_daily = FALSEin a platform's active INI file opts that platform out. The nightly worker seeds the variable into each platform INI as a commented-outTRUEdefault. One exception overrides the INI opt-out: a Drupal 7 platform missing the SA-CORE-2014-005 core patch is always fixed (and patched) regardless.
Interplay with Ægir tasks
Platform Verify (and the install flows that run it) invokes the
sudo-exposed fix-drupal-platform-ownership.sh wrapper with the backend
user as the target (--script-user) — that is, a platform Verify
re-locks ownership immediately, in any lock state. While unlock.info
remains in place the next nightly run restores the unlock; but a tenant
mid-upgrade who runs a platform Verify will find the code handed back to
the backend user on the spot. This is by design: Verify's job is to
converge the platform to the managed state.
The nightly ownership flip and the fixrepo tool
solve different axes: the lock manages who owns registered platforms on
a schedule; fixrepo repairs group-write and setgid on a tree (typically
an unregistered one) once, by hand. They compose without conflict — a
fixrepo-treated registered platform still gets its ownership managed
nightly.