Commit Graph

6623 Commits

Author SHA1 Message Date
Ollama
eec270d1aa fix: Address PR review comments
- Rename methods to camelCase (PSR-12): parseAttributeSearch, searchByAttributes, searchByAttributeValue, getAttributeSortDefinitionId
- Rename variables to camelCase (PSR-12)
- Add DATE attribute search support in searchByAttributeValue
- Fix get_definitions_by_flags to request typed payload (second param true)
- Handle both array and string return shapes for definition info
- Fix term-only search to merge with attribute matches instead of replacing
- Use strict emptiness checks (=== '' instead of empty())
- Sanitize definition_ids before SQL interpolation (array_map intval)
- Include DATE in attribute search conditions
2026-03-19 21:30:53 +00:00
Ollama
6ed6a3db52 style: Apply PSR-12 formatting
- Fix PHPDoc comment format in item_sort_columns() helper
- Remove duplicate blank line after properties in Item model
- Remove unused variable assignment in Items controller
2026-03-19 21:30:53 +00:00
Ollama
86173af352 Refactor: Use existing sanitizeSortColumn method with item_sort_columns helper
- Add item_sort_columns() helper function in tabular_helper.php
- Helper returns all sortable columns including dynamic attribute IDs
- Remove duplicate sanitizeSortColumnAttribute method from Items controller
- Remove unused ALLOWED_SORT_COLUMNS constant from Item model
- Reuses existing sanitizeSortColumn method from Secure_Controller
2026-03-19 21:30:53 +00:00
Ollama
2b74cc576e Refactor: Add ALLOWED_SORT_COLUMNS constant and reuse in sanitization
- Add Item::ALLOWED_SORT_COLUMNS constant for allowed sort columns
- Use constant in sanitizeSortColumnAttribute() instead of inline array
- Enables reuse across the codebase for sort column validation
2026-03-19 21:30:53 +00:00
Ollama
7887460c1a Implement Phase 3: Multi-attribute search AND logic and Phase 4: Sort by attribute columns
Phase 3 - Multi-attribute Search:
- Add parse_attribute_search() method to parse search syntax like
  'color: blue size: large' or 'color:blue AND size:large'
- Update search_by_attributes() to support AND/OR logic for multiple
  attribute queries
- Add search_by_attribute_value() private method for single value search

Phase 4 - Sort by Attribute Columns:
- Add get_attribute_sort_definition_id() method to detect attribute
  column sorting
- Update Item::search() to join attribute tables when sorting by
  attribute columns
- Update tabular_helper to make attribute columns sortable
- Add sanitizeSortColumnAttribute() method in Items controller to
  validate attribute definition IDs as sort columns

Fixes #2722 - sorting by attribute columns now works
2026-03-19 21:30:52 +00:00
Ollama
8994fb0c40 Add SHOW_IN_SEARCH flag to separate attribute search from visibility
Phase 2 implementation:
- Add SHOW_IN_SEARCH constant (value 8) to Attribute model
- Update Items controller to include searchable attributes when
  search_custom filter is enabled
- Add language strings for the new visibility flag
- Update Attributes controller to include new flag in form

This allows attributes to be searchable even if they are not
displayed in the items table, addressing issue #2919.

Fixes #2919
2026-03-19 21:30:52 +00:00
Ollama
a38d40f870 Refactor attribute search to fix pagination and multi-attribute search
- Add new search_by_attributes() method that returns matching item_ids
- Refactor search() method to use subquery approach instead of HAVING LIKE
- Fix pagination count issue (#2819) - get_found_rows() now returns correct count
- Enable combined search (attributes OR regular fields)
- GROUP_CONCAT still used for display but removed from search/count logic
- Fixes #2407 - multi-attribute search now works correctly

Related: #2819, #2407, #2722, #2919
2026-03-19 21:30:52 +00:00
Ollama
8b1f60c796 fix: create .env file before running tests in build-release workflow
The .env file is needed for CodeIgniter testing environment setup.
This matches what phpunit.yml workflow does.
2026-03-19 21:30:52 +00:00
Ollama
09c3e7f09f chore: trigger CI re-run 2026-03-19 21:30:52 +00:00
Ollama
ec96145084 fix: check for core tables not migrations table in initial migration (#4447)
When tests use refresh=true, CodeIgniter creates migrations table first,
so listTables() was returning that table and skipping initial schema.
Now checks for actual application tables (app_config, items, etc).
2026-03-19 21:30:52 +00:00
Ollama
107ed2b65c feat: replace database.sql with initial migration for automatic schema setup (#4447)
- Create initial migration that loads schema on fresh installs only
- Database schema is now version-controlled via migrations
- Remove database.sql build task from gulpfile
- Simplify Docker setup - no longer need sqlscript container
- Update CI workflows to rely on migrations for schema setup
- Update INSTALL.md documentation for automatic schema creation

Migrations now handle the complete database lifecycle:
- Fresh install: Initial migration creates full schema
- Existing install: Skips initial schema, continues normally
- No manual database.sql import needed
2026-03-19 21:30:52 +00:00
Ollama
fd6b668a79 feat: add initial schema migration for fresh database installs
- Create Migration_Initial_Schema that loads database.sql only on empty databases
- Existing installations skip this migration (tables already exist)
- Prevents duplicate column errors when migrations run on pre-populated schema
- Remove database.sql preloading from CI workflow - migrations handle schema setup
2026-03-19 21:30:52 +00:00
Ollama
1c09da8af2 Revert "fix: remove database.sql preloading for tests - migrations handle schema creation"
This reverts commit f25553edb5.
2026-03-19 21:30:52 +00:00
Ollama
8586a233b2 Revert "fix: load database.sql and mark migrations as run for tests"
This reverts commit bb6be3759a.
2026-03-19 21:30:52 +00:00
Ollama
eb79beaf2d fix: load database.sql and mark migrations as run for tests
- database.sql creates the base schema including all migration changes
- Insert migration history records to prevent migrations from re-running
- Migrations are upgrade scripts that expect base tables to exist
2026-03-19 21:30:52 +00:00
Ollama
d926ea200a fix: remove database.sql preloading for tests - migrations handle schema creation
Tests use DatabaseTestTrait with $migrate and $refresh, which means
migrations run to create the schema. Loading database.sql first causes
'Duplicate column' errors since migrations try to add columns that
already exist.
2026-03-19 21:30:52 +00:00
Ollama
e9010b8c9d fix: correct Token_lib test expectation - %b is valid strftime format
The string '%bad' contains '%b' which is a valid strftime format for
abbreviated month name, so it gets replaced (e.g., 'Marad' for March).
The test was incorrectly expecting '%bad' to remain unchanged.
2026-03-19 21:30:52 +00:00
Ollama
d7f89d25b2 fix: add CI_ENVIRONMENT=testing and ensure Seeds directory exists for tests 2026-03-19 21:30:52 +00:00
Ollama
af71e16b1a fix: correct tar file extension from .tar.gz to .tar 2026-03-19 21:30:52 +00:00
Ollama
63b65823e7 fix: address remaining PR review comments
- Use PR-scoped concurrency key to prevent cancellation across forks
- Reduce permissions: only release job needs contents:write
- Add bounded retry loop for MariaDB startup (30 attempts max)
- Derive Docker repo from DOCKER_USERNAME secret instead of hardcoding
- Delete codeql-analysis.yml (no longer needed)
- Update README: 'open-source' hyphenation, Docker image naming
2026-03-19 21:30:52 +00:00
Ollama
0d81207efb fix: address PR review comments and fix test job
- Fix concurrency key for push events (use github.ref instead of github.run_id)
- Add PHP setup and composer install in test job to fix missing PHPUnit
- Remove continue-on-error and || true from archive creation
- Remove || true from database initialization
- Upgrade softprops/action-gh-release from v1 to v2
- Update README to reflect MariaDB testing via Docker
2026-03-19 21:30:52 +00:00
Ollama
36c06cce89 Add multi-arch Docker builds (amd64/arm64), require tests to pass before Docker push 2026-03-19 21:30:52 +00:00
Ollama
ff97919c98 Remove Docker test container build, tests run directly on GitHub Actions 2026-03-19 21:30:52 +00:00
Ollama
8c12574d72 Convert Travis CI to GitHub Actions
- Create build-release.yml workflow to replace .travis.yml
- Build PHP 8.2 with required extensions
- Run PHPUnit tests with MariaDB container
- Build and push Docker images to Docker Hub
- Create/update unstable release on master push
- Add documentation for required secrets

Differences from Travis:
- Uses concurrency groups to cancel in-progress runs
- Separates build and release into distinct jobs
- Uses GitHub's native release action
- No separate SQL Docker image (can be added if needed)

Required secrets: DOCKER_USERNAME, DOCKER_PASSWORD
2026-03-19 21:30:52 +00:00
dependabot[bot]
e4b92b58c3 Bump jspdf from 4.2.0 to 4.2.1
Bumps [jspdf](https://github.com/parallax/jsPDF) from 4.2.0 to 4.2.1.
- [Release notes](https://github.com/parallax/jsPDF/releases)
- [Changelog](https://github.com/parallax/jsPDF/blob/master/RELEASE.md)
- [Commits](https://github.com/parallax/jsPDF/compare/v4.2.0...v4.2.1)

---
updated-dependencies:
- dependency-name: jspdf
  dependency-version: 4.2.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-17 19:06:05 +00:00
Ollama
dc1e448bc3 Fix review comments: remove redundant loop and add XSS escaping
- Remove redundant property assignment loop in Expenses.php
- Add esc() to employee name values to prevent XSS vulnerabilities
2026-03-17 15:32:16 +00:00
Ollama
24b2825b31 Fix: Restrict employee selection in expenses and receivings forms
Users without the 'employees' permission can no longer impersonate other
employees when creating or editing expenses and receivings. The employee
field is now restricted to the current user for new records and shows the
stored employee for existing records.

Changes:
- Expenses controller: Add permission check in getView() and postSave()
- Receivings controller: Add permission check in getEdit() and postSave()
- Form views: Conditionally display dropdown or read-only field

Fixes #3616
2026-03-17 15:32:16 +00:00
Ollama
38d672592b Add seed data to tests for proper integration testing
- Add setUp() to seed test data: items, sales, sales_items, sales_items_taxes
- Add tearDown() to clean up seeded data after tests
- Remove skip conditions since we now have guaranteed test data
- Add testTaxDataIsGroupedByTaxNameAndPercent to verify grouping
- Use narrow date range to isolate seeded data
2026-03-16 18:36:31 +00:00
Ollama
6f7e06e986 Rewrite tests to use database integration testing
Tests now:
- Use DatabaseTestTrait for real database integration
- Actually call getData() and getSummaryData() methods
- Verify row totals (subtotal + tax = total) from real queries
- Verify summary data matches sum of rows
- Test getDataColumns() returns expected structure
- Use assertEqualsWithDelta for float comparisons with tolerance

These tests exercise the actual SQL queries and verify the
mathematical consistency of the calculations returned.
2026-03-16 18:36:31 +00:00
Ollama
fda40d9340 Fix rounding consistency and update tests per review feedback
- Ensure total = subtotal + tax by deriving total from rounded components
- Use assertEqualsWithDelta for float comparisons in tests
- Add defensive null coalescing in calculateSummary helper
- Add missing 'count' key to test data rows
- Add testRoundingAtBoundary test case
2026-03-16 18:36:31 +00:00
Ollama
b49186ec7c Add unit tests for Taxes Summary Report calculations
Tests verify:
- Row totals add up (subtotal + tax = total)
- Summary totals match sum of row values
- Tax-included and tax-not-included modes calculate correctly
- Rounding consistency across calculations
- Negative values (returns) are handled correctly
- Zero tax rows are handled correctly
2026-03-16 18:36:31 +00:00
Ollama
8b56f61b8a Fix Taxes Summary Report totals not matching row values
The report had calculation inconsistencies where:
1. Per-line totals (subtotal + tax) didn't equal the total column
2. Column totals didn't match the sum of individual rows

Root cause: subtotal, tax, and total were calculated independently
using different formulas and rounding at different stages, leading to
cumulative rounding errors.

Fix:
- Use item_tax_amount from database as the source of truth for tax
- Derive subtotal from sale_amount (handling both tax_included and
  tax_not_included modes correctly)
- Calculate total = subtotal + tax consistently for each line
- Override getSummaryData() to sum values from getData() rows,
  ensuring summary totals match the sum of displayed rows

Fixes #4112
2026-03-16 18:36:31 +00:00
Ollama
9820beb0e1 Fix: Add Debit Card filter to Daily Sales and Takings
Add 'only_debit' filter to Daily Sales and Takings dropdown. Reuses
existing 'Sales.debit' language string for the filter label. Includes
filter default initialization in getSearch() to prevent PHP warnings.

Fixes #4439
2026-03-16 18:06:00 +00:00
Ollama
e01dad728f Add AGENTS.md with coding guidelines for AI agents 2026-03-16 18:02:50 +00:00
Ollama
234f930079 Fix strftime directives handling and tighten test assertions
- Remove incorrect %C mapping (was mapping century to full year)
- Add special handling for %C (century), %c (datetime), %n (newline), %t (tab), %x (date)
- Add %h mapping (same as %b for abbreviated month)
- Tighten edge-case test assertions to use assertSame/assertMatchesRegularExpression
- Add tests for new directives: %C, %c, %n, %t, %x, %h
2026-03-14 23:08:39 +00:00
Ollama
3001dc0e17 Fix: Pass parameter to generate() and add composite format tests
- Fixed bug where render() was not passing caller-supplied  to
  generate(), causing ad-hoc tokens to be ignored
- Added %F (yyyy-MM-dd) and %D (MM/dd/yy) composite date formats to
  the IntlDateFormatter pattern map
- Added test coverage for composite date format directives (%F, %D, %T, %R)
2026-03-14 23:08:39 +00:00
Ollama
3ba207e8b9 Use CIUnitTestCase for consistency with other tests 2026-03-14 23:08:39 +00:00
Ollama
d684c49ebd Fix Token_lib::render() for PHP 8.4 compatibility
- Replaced deprecated strftime() with IntlDateFormatter
- Added proper handling for edge cases:
  - Strings with '%' not in date format (e.g., 'Discount: 50%')
  - Invalid date formats (e.g., '%-%-%', '%Y-%q-%bad')
  - Very long strings
- Added comprehensive unit tests for Token_lib
- All date format specifiers now mapped to IntlDateFormatter patterns
2026-03-14 23:08:39 +00:00
Ollama
071e641f95 Fix stored XSS via stock location name
Add esc() to stock_name output in sales/register.php and receivings/receiving.php

GHSA-vmm7-g33q-qqr2
2026-03-14 15:35:32 +00:00
Ollama
48af67bd00 Fix stored XSS in gcaptcha_site_key on login page 2026-03-14 15:35:16 +00:00
Ollama
7cb1d95da7 Fix: Host Header Injection vulnerability (GHSA-jchf-7hr6-h4f3)
Security: Prevent Host Header Injection attacks by validating HTTP_HOST
against a whitelist of allowed hostnames before constructing the baseURL.

Changes:
- Add getValidHost() method to validate HTTP_HOST against allowedHostnames
- If allowedHostnames is empty, log warning and fall back to 'localhost'
- If host not in whitelist, log warning and use first allowed hostname
- Update .env.example with allowedHostnames documentation
- Add security configuration section to INSTALL.md
- Add unit tests for host validation

This addresses the security advisory where the application constructed
baseURL from the attacker-controllable HTTP_HOST header, allowing:
- Login form phishing via manipulated form actions
- Cache poisoning via poisoned asset URLs

Fixes GHSA-jchf-7hr6-h4f3
2026-03-14 15:34:21 +00:00
jekkos
bafe3ddf1b Fix stored XSS vulnerability in Attribute Definitions (GHSA-rvfg-ww4r-rwqf) (#4429)
* Fix stored XSS vulnerability in Attribute Definitions

GHSA-rvfg-ww4r-rwqf: Stored XSS via Attribute Definition Name

Security Impact:
- Authenticated users with attribute management permission can inject XSS payloads
- Payloads execute when viewing/editing attributes in admin panel
- Can steal session cookies, perform CSRF attacks, or compromise admin operations

Root Cause:
1. Input: Attributes.php postSaveDefinition() accepts definition_name without sanitization
2. Output: Views echo definition_name without proper escaping

Fix Applied:
- Input sanitization: Added FILTER_SANITIZE_FULL_SPECIAL_CHARS to definition_name and definition_unit
- Output escaping: Added esc() wrapper when displaying definition_name in views
- Defense-in-depth: htmlspecialchars on attribute values saved to database

Files Changed:
- app/Controllers/Attributes.php - Sanitize inputs on save
- app/Views/attributes/form.php - Escape output on display
- app/Views/attributes/item.php - Escape output on display

* Remove input sanitization, keep output escaping only

Use escaping on output (esc() in views) as the sole XSS prevention
measure instead of sanitizing on input. This preserves the original
data in the database while still protecting against XSS attacks.

* Add validation for definition_fk foreign key in attribute definitions

Validate definition_group input before saving:
- Must be a positive integer (> 0)
- Must exist in attribute_definitions table
- Must be of type GROUP to ensure data integrity

Also add translation for definition_invalid_group error message
in all 45 language files (English placeholder for translations).

* Refactor definition_fk validation into single conditional statement

* Add esc() to attribute value outputs for XSS protection

- Add esc() to TEXT input value in item.php
- Add esc() to definition_unit in form.php

These fields display user-provided content and need output escaping
to prevent stored XSS attacks.

* Refactor definition_group validation into separate method

Extract validation logic for definition_fk into validateDefinitionGroup()
private method to improve code readability and reduce method complexity.

Returns:
- null if input is empty (no group selected)
- false if validation fails (invalid group)
- integer ID if valid

* Add translations for definition_invalid_group in all languages

- Added proper translations for 28 languages (de, es, fr, it, nl, pl, pt-BR, ru, tr, uk, th, zh-Hans, zh-Hant, ro, sv, vi, id, el, he, fa, hu, da, sw-KE, sw-TZ, ar-LB, ar-EG)
- Set empty string for 14 languages to fallback to English (cs, hr-HR, bg, bs, ckb, hy, km, lo, ml, nb, ta, tl, ur, az)

---------

Co-authored-by: Ollama <ollama@steganos.dev>
2026-03-14 15:33:58 +00:00
jekkos
c482e75304 Fix DECIMAL attribute not respecting locale format (#4422)
* Fix DECIMAL attribute not respecting locale format

Issue: DECIMAL attribute values were displayed as raw database values
instead of being formatted according to the user's locale settings.

Fix:
1. Modified Attribute::get_definitions_by_flags() to optionally return
   definition types along with names (new $include_types parameter)
2. Updated expand_attribute_values() in tabular_helper.php to detect
   DECIMAL attributes and apply to_decimals() locale formatting
3. Updated callers (Reports, Items table) to pass include_types=true
   where attributes are displayed

The DECIMAL values in table views (items, sales reports, receiving reports)
now respect the configured locale number format, matching DATE attributes
which already use locale-based formatting.

* Apply PSR-12 camelCase naming to new variables

Response to PR review comments:
- Rename  to
- Rename  to
- Rename  to

---------

Co-authored-by: Ollama <ollama@steganos.dev>
2026-03-13 21:23:52 +00:00
jekkos
afc2f82dc6 Fix PHPUnit environment variables not being set (#4434)
PHPUnit 10+/11+ requires force="true" attribute on <env> elements
to properly set environment variables. Without this attribute, the
database connection env vars were not being set during test bootstrap,
causing tests to fail silently with empty junit.xml output.

This fix adds force="true" to all <env> elements in phpunit.xml.dist.

Co-authored-by: Ollama <ollama@steganos.dev>
2026-03-13 18:54:29 +00:00
jekkos
ce411707b4 Fix SQL injection in suggestions column configuration (#4421)
* Fix SQL injection in suggestions column configuration

The suggestions_first_column, suggestions_second_column, and
suggestions_third_column configuration values were concatenated
directly into SQL SELECT statements without validation, allowing
SQL injection attacks through the item search suggestions.

Changes:
- Add whitelist validation in Config controller to only allow
  valid column names (name, item_number, description, cost_price,
  unit_price)
- Add defensive validation in Item model's get_search_suggestion_format()
  and get_search_suggestion_label() methods
- Default invalid values to 'name' column for safety
- Add unit tests to verify malicious inputs are rejected

This is a critical security fix as attackers with config permissions
could inject arbitrary SQL through these configuration fields.

Vulnerability reported as additional injection point in bug report.

* Refactor: Move allowed suggestions columns to Item model constants

Extract the list of valid suggestion columns into two constants in the Item model for better cohesion:
- ALLOWED_SUGGESTIONS_COLUMNS: valid column names
- ALLOWED_SUGGESTIONS_COLUMNS_WITH_EMPTY: includes empty string for config validation

This consolidates the validation logic in one place and makes it reusable across Config controller and Item model.

* Address PR review comments: improve validation and code quality

Changes:
- Use camelCase naming for validateSuggestionsColumn() method (PSR-12)
- Add field-aware validation with different fallbacks for first vs other columns
- Handle non-string POST input by checking is_string() before validation
- Refactor duplicate validation logic into suggestionColumnIsAllowed() helper
- Use consistent camelCase variable names ($suggestionsFirstColumn)
- Update tests to validate constants and behavior rather than implementation
- Tests now focus on security properties of the allowlist itself

The validation now properly handles:
- First column: defaults to 'name' when invalid
- Second/Third columns: defaults to '' (empty) when invalid
- Non-string inputs: treated as invalid with appropriate fallback

---------

Co-authored-by: Ollama <ollama@steganos.dev>
2026-03-13 18:13:54 +00:00
jekkos
37c6e22fc4 Update SECURITY.md with published security advisories (#4431)
- Add Security Advisories section with 4 published CVEs
- Include CVE ID, vulnerability description, CVSS score, publication date, fixed version, and reporter credits
- Update supported versions table to reflect current state (>= 3.4.2)
- Add link to GitHub Security Advisories page for complete list

CVEs added:
- CVE-2025-68434: CSRF leading to Admin Creation (8.8)
- CVE-2025-68147: Stored XSS in Return Policy (8.1)
- CVE-2025-66924: Stored XSS in Item Kits (7.2)
- CVE-2025-68658: Stored XSS in Company Name (4.3)

Co-authored-by: Ollama <ollama@steganos.dev>
2026-03-13 17:53:32 +00:00
jekkos
3c7ece5c33 Fix permission bypass in Sales.getManage() access control (#4428)
The redirect() in getManage() returned a RedirectResponse that was never
executed, allowing unauthorized access to reports_sales. Updated method
signature to return ResponseInterface|string and properly return the
redirect response.

Refs: GHSA-94jm-c32g-48r5

Co-authored-by: Ollama <ollama@steganos.dev>
2026-03-13 17:52:07 +00:00
jekkos
02fccaf43f Fix XSS vulnerability in tax invoice view (#4432)
Co-authored-by: Ollama <ollama@steganos.dev>
2026-03-13 16:09:04 +00:00
jekkos
ee4d44ed39 Fix IDOR vulnerability in password change (GHSA-mcc2-8rp2-q6ch) (#4427)
* Fix IDOR vulnerability in password change (GHSA-mcc2-8rp2-q6ch)

The previous authorization check using can_modify_employee() was too
permissive - it allowed non-admin users to change other non-admin users'
passwords. For password changes, users should only be able to change
their own password. Only admins should be able to change any user's
password.

This fix replaces the can_modify_employee() check with a stricter
authorization that only allows:
- Users to change their own password
- Admins to change any user's password

Affected endpoints:
- GET /home/changePassword/{employee_id}
- POST /home/save/{employee_id}

Added tests to verify non-admin users cannot access or change other
non-admin users' passwords.

* Address PR review feedback

- Replace header/exit redirect with proper 403 response in getChangePassword
- Refactor createNonAdminEmployee helper to accept overrides array
- Simplify tests by reusing the helper
- Update tests to expect 403 response instead of redirect

---------

Co-authored-by: Ollama <ollama@steganos.dev>
2026-03-13 12:13:21 +01:00
jekkos
fa3f257e7b Fix PHPUnit test configuration for database connectivity (#4430)
- Add database.tests.* environment variables to phpunit.xml.dist
- Set hostname to 127.0.0.1 to match CI MariaDB container
- Add MYSQL_* env vars for Database.php compatibility
- Tests were not running because database connection failed silently

Co-authored-by: Ollama <ollama@steganos.dev>
2026-03-13 10:38:37 +01:00