chore(hooks): add pre-commit php -l hook (opt-in) - #29
Merged
Conversation
Adds .githooks/pre-commit that runs `php -l` on every staged .php file (diff-filter ACMR, NUL-delimited for safe handling of paths with spaces) and aborts the commit on any parse error. Mirrors the "PHP Lint" job in .github/workflows/ci.yml so syntax errors surface locally instead of after a push. The hook is opt-in per clone. A new scripts/install-hooks.sh sets `git config core.hooksPath .githooks`, which is the canonical post-2.9 way to ship hooks alongside the repo without requiring a manual copy into .git/hooks/. Behaviour: - 0 staged .php files: exit 0 silently. - All staged .php files lint clean: exit 0 with one-line success. - Any parse error: print the offending file + php -l output, exit 1. Bypass with `git commit --no-verify` if intentional. - php not on PATH: warn and skip (don't block a commit on a missing toolchain — CI is the authoritative check). Exercised end-to-end in a sandbox git repo for all three branches (clean / mixed-with-broken / no-php-staged); rc was 0 / 1 / 0 respectively. README gains a "Developer hooks (optional)" subsection pointing at install-hooks.sh. gap-analysis.md item 4 from the post-PR-27 deferred list is now struck through. Closes the "smallest deferred item" called out after PR #28 merged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 15, 2026
bitsandbots
added a commit
to jleog/inventory
that referenced
this pull request
May 22, 2026
Nine `<form method="post" action="...?>` openings spanning 8 edit
pages dropped the closing `"` of the action attribute, then placed
`<?php echo csrf_field(); ?>` on the next line and closed the quote
*after* that. After PHP rendered, the browser saw:
<form method="post" action="../path.php?id=42
<input type="hidden" name="csrf_token" value="...">"
class="clearfix">
The action attribute terminated at the next `"` (the `"hidden"` of the
csrf input), turning `name="csrf_token"` and `value="..."` into form
attributes rather than a real hidden input. End result: the CSRF
token was never submitted with the form. Any POST therefore failed
`verify_csrf()` and bounced through the redirect path, making these
edit screens effectively unusable for their intended action:
- users/edit_group.php
- users/edit_account.php
- users/edit_category.php
- products/edit_category.php
- products/edit_product.php
- sales/edit_order.php
- sales/add_sale_by_search.php (two forms in this file)
- sales/add_sale_to_order.php
Fix is mechanical and identical at every site: close the action
attribute on its own line, then place `<?php echo csrf_field(); ?>`
on the next line inside the form body, matching the already-correct
pattern in users/edit_user.php:116-117 and the other working
edit pages.
No schema, route, or behaviour change beyond the forms now actually
submitting their CSRF token. Full test suite (5/5 suites, 43 tests)
passes; `php -l` clean on all 8 touched files; pre-commit hook
(PR bitsandbots#29) green.
Found incidentally while reviewing migration 004 follow-ups noted
in next_steps_inventory.md item 4.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
.githooks/pre-committhat runsphp -lon every staged.phpfile and aborts the commit on a parse error. Mirrors the "PHP Lint" job in.github/workflows/ci.yml, so syntax errors surface locally instead of after a push.scripts/install-hooks.shto opt-in per clone (git config core.hooksPath .githooks).docs/gap-analysis.mditem 4 is struck through.| Staged set | Result |
|---|---|
| 0
.phpfiles | exit 0, silent || all clean | exit 0, one-line green success |
| any parse error | exit 1, prints offending file +
php -loutput ||
phpnot on PATH | warn, skip (don't block on missing toolchain) |Bypass with
git commit --no-verifyif intentional.git initrepo, run hook against clean file → rc=0 with green messagebash tests/run.sh— 4/4 suites passedbash scripts/install-hooks.shlocally and confirmcore.hooksPathflips to.githooks🤖 Generated with Claude Code