Answering Y at the schema prompt no longer takes the manual path - #1733
Merged
Merged
Conversation
`read` returns exactly what the terminal sent. It strips the newline and
nothing else, so a client that ends its lines with CRLF delivers $'Y\r' -- and
that matches none of updateDB()'s patterns. A deliberate "Y" therefore fell
through to the manual browser branch, which:
- runs no migration at all
- prints the schema install token to stdout
- is followed by verifySchemaDeploy(), which then reported "Done" because the
schema happened to be current already
So the run looked like a success and had deployed nothing. Reported from a live
upgrade: the operator typed Y, the transcript shows Y, and the manual
instructions printed anyway. On a server that DID need migrating, the same slip
leaves it unmigrated under that same success line two steps later. A trailing
or leading space did it too.
normalizeAnswer() strips the carriage return and trims, and the value is
normalized before the case rather than inside the read branch, so every source
of it is covered -- including bin/installfog.sh's -y. The read also gains -r,
so a backslash in an answer is not an escape.
The direction of the fallthrough is deliberately unchanged: an answer that is
still unrecognized after normalization opts out, exactly as before. Only the
characters a terminal adds by itself stop deciding it.
Second, smaller thing, from the same report. The installer asked "install/update
the FOG database schema now?" on a database with every indexed step already
applied, and then migrated nothing -- which reads as the answer having been
ignored. The question is now skipped in that case and the state is stated
instead.
The DEPLOY still runs there. It is not only migrations: it seeds required rows,
and Schema::seedRequiredRows() is written for precisely the state where the
indexed steps are all applied and rows are missing -- its own docblock records
finding that by deleting a seeded row on a server at vValue == FOG_SCHEMA and
watching the updater redirect instead of restoring it. Skipping the step would
make that repair unreachable on the servers that need it, so the new predicate
gates the QUESTION and never the deploy.
schemaStepCount() is factored out of verifySchemaDeploy() rather than copied,
because two copies of that grep would be two things to keep in step, and the
cost of them disagreeing is an installer that asks about a migration it then
reports as unnecessary. Unknown on either side -- a fresh install with no
schemaVersion table, DB_external=yes, or a schema.php whose formatting stopped
matching -- keeps the old behaviour: ask, and deploy.
tests/schema-prompt-answers.test.sh covers both halves on generated fixtures
with schemaVersionInDB() stubbed: no install, no database, no network, no root.
Nineteen of its assertions fail without normalizeAnswer(); moving the call
after the case fails the wiring assertions alone; and making a zero step count
read as "done" fails exactly the two that exist to refuse it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps28eGTALgieR6TBUSafVg
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.
The bug
From the reporting server's own console. The operator typed
Y:Note what is absent: there is no
* Updating Database....step. The[Yy]case never matched, so the automatic deploy never ran. The install then reported
Verifying database schema...Done— truthfully, because that server's schemawas already current.
readreturns exactly what the terminal sent. It strips the newline and nothingelse, so a client ending its lines with CRLF delivers
$'Y\r', which matchesnone of the patterns:
The manual branch is not a harmless fallback.
updateDB()'s own comment says it"verifies nothing and hands the install token out on stdout", and this is how
it gets reached by accident. On a server that genuinely needed migrating, the
same slip leaves it unmigrated under a
Donetwo lines later.The fix
normalizeAnswer()strips the carriage return and trims. It is applied beforethe case, not inside the read branch, so every source of the value goes
through it — including
bin/installfog.sh's-y. The read gains-r.The direction of the fallthrough is deliberately unchanged. An answer still
unrecognised after normalisation opts out, exactly as today. Only the characters
a terminal adds by itself stop deciding it. (Inverting it was considered and
rejected: it would make
nopedeploy.)Second, smaller thing, from the same report
The question implies pending work. Asking it on a database with every indexed
step applied — and then migrating nothing — reads as the answer having been
ignored. It is now skipped in that case, and the state stated instead:
The deploy still runs there, and that is the load-bearing part. The POST is
not only migrations: it seeds required rows, and
Schema::seedRequiredRows()exists for precisely the state where the indexed steps are applied and rows are
missing. Its docblock records finding that by deleting a seeded row on a server
at
vValue == FOG_SCHEMAand watching the updater redirect instead of restoringit. Skipping the step would make that repair unreachable on the servers that
need it — so the new predicate gates the question, never the deploy.
schemaStepCount()is factored out ofverifySchemaDeploy()rather thancopied. Two copies of that grep would be two things to keep in step, and the
cost of disagreement is an installer that asks about a migration it then reports
as unnecessary.
Unknown on either side keeps today's behaviour exactly — ask, and deploy:
schemaVersiontable)DB_external=yes(refuses to look)schema.phpwhose formatting stopped matchingTesting
tests/schema-prompt-answers.test.sh— 37 assertions on generated fixtures withschemaVersionInDB()stubbed. No install, no database, no network, no root.Three groups, because they fail differently: what normalisation returns; where
each answer routes; and the wiring —
normalizeAnswer()can be correct andunreached, so the call's existence and its position before the case are both
pinned.
Mutation-tested:
normalizeAnswercalled after the caseNeighbouring suites, all unchanged:
installer-tls-verification20/20,revert-offer46/46,install-settings-resolution50/50,web-chain-external-leaf17/17,web-chain-feedback9/9,installer-schema-deployok.selfcall-verificationreports 14/4 identically before and after on thismachine — empty-CN
-subjfixture failures specific to it, not this change.Not verified locally
phpstan(both passes) did not run — novendor/. This adds no PHP, sothe risk is low, but the
tests/pass baselines occurrence counts.schemaVersionInDB()is stubbed, so thepredicate's inputs are exercised but not its live query. The end-to-end path
is what the reporter will re-test.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Ps28eGTALgieR6TBUSafVg