Port: string identifiers read as foreign keys, and php-fpm error log ownership - #1167
Merged
Conversation
Port of working-1.6 GH-1153 and GH-1162, which landed there separately. Both halves are here in one commit because splitting them serves nobody on a maintenance branch: the first alone leaves an object that saves and then fails validation forever after. FOGController infers "this is an integer id" from the key's name ending in "id". Right for every real foreign key in the tree, wrong for a string identifier spelled the same way, and the two failure modes differ. Required: throws "Required database field is empty: <key>" about a field that is filled in. Optional: filter_var fails, the value becomes 0, and the real one is lost with no error anywhere. The inference lives in TWO methods, save() and isValid(), each with its own copy. $databaseFieldsNotInt lets a model say which of its *id keys is a string, and both methods now honor it -- the name is a proxy for the column's type, and the model is the only thing that knows the type. Two casualties on this branch, and the list is exhaustive rather than the ones that got noticed: every *id key every model declares was resolved to its (table, column) pair and typed against a real 1.5.10 install's information_schema, and all 38 plugin *id columns were typed from their own Schema::createTable() lists. Everything else is an integer. inventory.sysuuid -> iSystemUUID, varchar(255). The SMBIOS system UUID was written as 0 on every inventory write. Reproduced on the 1.5 lab server against its own database: sent 4C4C4544-0031-3010-8039-CAC04F565831, stored '0'. With this commit overlaid, the same write stores the UUID. The probe row was destroyed and the live tree was never touched. taskLog.taskID, mediumtext. 1.6 fixed the column instead (schema 336, GH-1156). A column type change is a data migration, and a maintenance branch is the wrong place to run one over a table that can hold every task a server has ever run -- so this does the same job without touching the schema. tests/databasefields-notint.test.php pins both methods separately, including that each builds its own lookup before the branch that reads it. It deliberately carries no column-type sweep: 1.6's version reads commons/schema-expected.php, which this branch does not have, and deriving types by regex from schema.php's accumulated ALTER statements gives wrong answers -- it matched an msState belonging to a different table when tried. The sweep was done once, properly, against a live schema; the test pins its findings by name. Eight mutations verified, all caught, including a comment-only one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017aBSWrDArXHTpKWkkN27LR
Port of working-1.6 GH-1165. This branch has the same defect: it rewrites the php-fpm pool to run as $apacheuser and leaves the packaged log owned by the distro's user. The pool then cannot open the file named by its own php_admin_value[error_log], so every error_log() call from FOG's PHP is discarded. It fails more quietly than the session directory the block above already re-owns: nothing reports it, and the log sits at zero bytes looking like an install with no errors. Measured on a Fedora nginx install -- /var/log/php-fpm owned apache:root, www-error.log owned apache:apache, pool running as nginx, `test -w` refusing both. The file is re-owned unconditionally and created first if the pool has never managed to write it. The directory only when its own basename marks it as php-fpm's: on Debian the log sits directly in /var/log, and chowning that to the web user would be a far worse bug than this one. Both parses are guarded the way the session-path chown above is -- absolute, not "/", parent must exist -- so "syslog", or a commented-out line, resolves to nothing rather than to a chown of somewhere that matters. Simulated against both layouts and three refusal cases before it went in, and verified on the 1.6 server by writing through the pool user afterwards. logrotate keeps the ownership: the packaged php-fpm rule carries no `create` line. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017aBSWrDArXHTpKWkkN27LR
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ports the two of today's
working-1.6fixes that this branch actually has.1. String identifiers read as foreign keys — #1153 + #1162
FOGControllerinfers "this is an integer id" from the key's name ending inid. Right for every real foreign key in the tree, wrong for a stringidentifier spelled the same way. The inference lives in two methods,
save()andisValid(), each with its own copy — which is the trap: fixingonly
save()leaves an object that saves and then fails validation foreverafter. Both are fixed here, in one commit, because splitting them serves nobody
on a maintenance branch.
The casualty list is exhaustive, not "the ones that got noticed"
Every
*idkey every model declares was resolved to its(table, column)pairand typed against a real 1.5.10 install's
information_schema; all 38plugin
*idcolumns were typed from their ownSchema::createTable()lists.Exactly two are not integers:
inventory.sysuuidiSystemUUIDvarchar(255)0on every inventory writetaskLog.taskIDtaskIDmediumtext0Reproduced and fixed on a real 1.5 server
Shadow tree in
~on the 1.5 lab box, running against its own database — thelive tree was never touched (
grepfor the guard on/var/www/html/fogafter:0):
Both probe rows were destroyed;
inventoryis back to 0 rows.taskLog.taskIDis fixed differently from 1.6, on purpose1.6 fixed the column (schema 336, #1156). A column type change is a data
migration, and a maintenance branch is the wrong place to run one over a table
that can hold every task a server has ever run. Declaring the field does the
same job with no schema change. The comment in
tasklog.class.phpsays so, andpoints at #1156.
2. php-fpm's error log — #1165
Same defect here: the installer rewrites the pool to run as
$apacheuserandleaves the packaged log owned by the distro's user, so the pool cannot open the
file named by its own
php_admin_value[error_log]and everyerror_log()call from FOG's PHP is discarded. The log sits at zero bytes looking like an
install with no errors, and nothing reports it.
Guarded exactly like the session-path
chowndirectly above it; the directoryis only re-owned when its own basename marks it as php-fpm's, because on Debian
the log sits directly in
/var/log.Not ported: #1163
The nginx query-string fix does not apply to this branch, and the check was not
"it looks similar":
location ~andzero
try_filesinlib/common/functions.sh; only the Apache rewrite, whichcarries
[QSA,L]and was never affected;Routereads no query parameters here — noINPUT_GET, noQUERY_STRING, no$_GET[, and noqueryParam()to make public;Test
tests/databasefields-notint.test.phppins both methods separately, includingthat each builds its own lookup before the branch that reads it, plus the two
casualties by name. It deliberately carries no column-type sweep: 1.6's
version reads
commons/schema-expected.php, which this branch does not have,and deriving types by regex from
schema.php's accumulatedALTERstatementsgives wrong answers — it matched an
msStatebelonging to a different tablewhen tried. The sweep was done once, properly, against a live schema; the test
pins its findings.
Eight mutations verified, all caught, including a comment-only one.
sh tests/run-all.sh→ 8 passed, 0 failed.🤖 Generated with Claude Code
https://claude.ai/code/session_017aBSWrDArXHTpKWkkN27LR