fix(core): the int request accessors read an array as the number 1 (#1087 passo 1) - #1088
Merged
Merged
Conversation
…1087) RequestInput::get_post_int() e get_get_int() faziam absint( wp_unslash( ... ) ) sem conferir o tipo, enquanto get_post_string()/get_get_string() sempre conferiram com is_string. absint( array('45') ) e 1 e absint( array() ) e 0 — os dois em silencio, sem aviso do PHP, e 1 e um id, uma contagem e um teto plausiveis. E a mesma assimetria que o SettingsReader tinha ate o #1086, em outra classe, e o mesmo cast que no #1075 transformou uma duracao de slot em um minuto. A guarda nos dois helpers corrige 74 chamadas de uma vez. Alem delas, 39 casts diretos sobre superglobal, em 10 arquivos, passam a ir pelos helpers — 22 no tab-rate-limit, onde um POST com array achatava para 1 todos os tetos (max_per_hour, max_per_day, cooldown_seconds, max_logs, retention_days); 3 no settings-action-handler, onde as janelas de carencia viravam 1 dia e a do save_days persistia; 7 form_id na superficie publica, sem ganho de privilegio porque form_id nao e segredo e a validacao seguinte continua valendo. Mais dois itens que a triagem dos 20 gravadores levantou: - consume_ticket() atribuia offset sobre o retorno de get_post_meta( ..., true ), que e '' quando a meta nao existe — em PHP 8 isso e fatal, nao aviso. O teste novo reproduz o TypeError contra o codigo antigo. NAO e alcancavel hoje: o caminho exige is_ticket, que ja pressupoe a config lida como array. Fica a forma do #1058 tornada segura, nao um bug vivo consertado. - os 6 wp_kses_post sobre $_POST no audience passam por uma guarda de escalar. O helper e privado na classe porque ela e o unico consumidor no plugin — compartilhar com um chamador so seria fachada que nao estreita nada (#1079). O que o wp_kses_post real faz com um array nao foi verificado: nao ha WordPress neste ambiente. O teste prova a guarda, nao o comportamento antigo. Regua de linhas segue em 0/45. Nivel 9 do repositorio: 2584 para 2535. Esta PR nao mira em zerar nada — o alvo e o defeito, nao o numero. Refs #1087, #1060, #1075, #1086, #1058 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012XWx9qJdjZdAq8crxM9GCU
PublicFormsExportSourceTest faz alias mock de RequestInput e stubava so get_user_ip, get_post_string, get_get_key, get_get_int e has_get. Rotear request_form_id() pelo get_post_int() fez o codigo chamar um metodo que o mock nao conhece — o Mockery rejeita, e os tres testes que esperavam RuntimeException receberam BadMethodCallException. Mesmo padrao que o CLAUDE.md registra para as divisoes Reader/Writer: um alias mock precisa stubar todo metodo que o codigo sob teste passa a chamar. Os 11 alias mocks da classe passam a stubar get_post_int com a semantica do helper real, guarda de escalar inclusa. Junto, uma anotacao que a mudanca deixou inerte: o // phpcs:ignore ... -- absint() sanitizes sobre request_form_id(), numa linha que nao le mais superglobal. Removida e conferida: PHPCS segue limpo sem ela. E a classe de residuo que os #1031/#1035 varreram. Refs #1087 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012XWx9qJdjZdAq8crxM9GCU
Coverage Report for CI Build 34065938230Warning Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes. Warning No base build found for commit Coverage: 89.973%Details
Uncovered Changes
Coverage RegressionsRequires a base build to compare against. How to fix this → Coverage Stats
💛 - Coveralls |
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.
Passo 1 de três da #1087. Os passos 2 (guarda estático) e 3 (recorte público) vêm em PRs separadas — esta issue fica aberta.
O defeito que paga a PR
RequestInputtem duas famílias de acessores e só uma confere o tipo:absint( array('45') )é1eabsint( array() )é0— os dois em silêncio, sem aviso do PHP. E1é um id plausível, uma contagem plausível e um teto plausível. É o mesmo cast que no #1075 transformou uma duração de slot em um minuto, e a mesma assimetria que oSettingsReadercarregava até o #1086, agora em outra classe.A guarda nos dois helpers corrige 74 chamadas de uma vez.
Os 39 casts diretos
Além das 74, 39 sites em 10 arquivos castavam superglobal sem passar por helper nenhum. Todos admin-only, nenhum abre acesso:
settings/tabs/class-ffc-tab-rate-limit.phpmax_per_hour,max_per_day,cooldown_seconds,max_logs,retention_days…) viram 1 — o rate limit inteiro achatadofrontend/class-ffc-public-csv-download.phpform_idcai em 1; sem ganho de privilégio —form_idnão é segredo e a validação de post type + acesso público segue valendoadmin/class-ffc-settings-action-handler.phpsave_dayspersistesettings/tabs/class-ffc-tab-geolocation.phpmax()— inócuoMais dois itens da triagem
consume_ticket()atribuía offset sobre o retorno deget_post_meta( …, true ), que é''quando a meta não existe. Em PHP 8 isso é fatal, não aviso — o teste novo reproduz oTypeError: Cannot access offset of type string on stringcontra o código antigo. Não é alcançável hoje: o caminho exigeis_ticket, que já pressupõe a config lida como array emcheck( array $form_config, … ). Fica a forma do #1058 tornada segura, não um bug vivo consertado — e a PR diz isso com essas palavras em vez de inflar o achado.Os 6
wp_kses_postsobre$_POSTno audience passam por uma guarda de escalar. O helper é privado na classe porque ela é o único consumidor no plugin inteiro — um helper compartilhado com um chamador só seria fachada que não estreita nada (precedente #1079). Ressalva: o que owp_kses_postreal faz com um array não foi verificado, porque não há WordPress neste ambiente; no teste, o valor que aparece contra o código antigo é artefato do stubreturnArg. O teste prova a guarda, não o comportamento antigo — a #1087 registra isso como não verificado.Testes
Três discriminantes, cada um rodado contra o código antigo com os valores que as tabelas acima afirmam:
Mais dois de preservação de comportamento, que passam dos dois lados de propósito (
get_post_int_casts_through_absint, e o valor string do audience seguindo inalterado).Uma quebra minha, e a correção
A primeira rodada da suíte fechou vermelha:
PublicFormsExportSourceTestfaz alias mock deRequestInpute stubava só cinco métodos. Rotearrequest_form_id()peloget_post_int()fez o código chamar um sexto, e o Mockery rejeitou — três testes que esperavamRuntimeExceptionreceberamBadMethodCallException. É o padrão que oCLAUDE.mdregistra para as divisões Reader/Writer: um alias mock precisa stubar todo método que o código sob teste passa a chamar. Os 11 alias mocks da classe agora stubamget_post_intcom a semântica do helper real.Junto veio uma anotação que a mudança deixou inerte —
// phpcs:ignore … -- absint() sanitizessobre uma linha que não lê mais superglobal. Removida, e conferido que PHPCS segue limpo sem ela: é a classe de resíduo que os #1031/#1035 varreram.Validação
phpcs-tests.xml.dist: limposO que esta PR não faz, de propósito: não zera nada. Os 296 erros do recorte de gravadores continuam de pé, e os 2535 do repositório também. O alvo é o defeito, não o número.
Refs #1087, #1060, #1075, #1086, #1058
🤖 Generated with Claude Code
https://claude.ai/code/session_012XWx9qJdjZdAq8crxM9GCU
Generated by Claude Code