Skip to content

chore(hooks): add pre-commit php -l hook (opt-in) - #29

Merged
bitsandbots merged 1 commit into
mainfrom
feature/precommit-php-lint-hook
May 15, 2026
Merged

chore(hooks): add pre-commit php -l hook (opt-in)#29
bitsandbots merged 1 commit into
mainfrom
feature/precommit-php-lint-hook

Conversation

@bitsandbots

Copy link
Copy Markdown
Owner
  • Adds .githooks/pre-commit that runs php -l on every staged .php file 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.
  • Adds scripts/install-hooks.sh to opt-in per clone (git config core.hooksPath .githooks).
  • README gains a "Developer hooks (optional)" subsection; docs/gap-analysis.md item 4 is struck through.
    | Staged set | Result |
    |---|---|
    | 0 .php files | exit 0, silent |
    | all clean | exit 0, one-line green success |
    | any parse error | exit 1, prints offending file + php -l output |
    | php not on PATH | warn, skip (don't block on missing toolchain) |
    Bypass with git commit --no-verify if intentional.
  • Sandbox git init repo, run hook against clean file → rc=0 with green message
  • Sandbox repo, stage clean + broken file → rc=1, prints "syntax error in b.php" + parse-error detail
  • Sandbox repo, stage only a non-php file → rc=0 silent (no work to do)
  • Full test suite: bash tests/run.sh — 4/4 suites passed
  • Reviewer: run bash scripts/install-hooks.sh locally and confirm core.hooksPath flips to .githooks
    🤖 Generated with Claude Code

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>
@bitsandbots
bitsandbots merged commit 0e49a01 into main May 15, 2026
2 checks passed
@bitsandbots
bitsandbots deleted the feature/precommit-php-lint-hook branch May 15, 2026 14:49
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant