Skip to content

Converge: merge all 2.1 changes into master (keep master's features/fixes) - #525

Merged
navneetkumar-pim-webkul merged 60 commits into
masterfrom
sync/merge-2.1-into-master
Jun 26, 2026
Merged

navneetkumar-pim-webkul merged 60 commits into
masterfrom
sync/merge-2.1-into-master

Conversation

@navneetkumar-pim-webkul

Copy link
Copy Markdown
Collaborator

Goal

Bring all remaining 2.1 changes into master while preserving master's own features and fixes. After this merge, origin/2.1 is a full ancestor of master — the branches are converged.

How conflicts were resolved (86 total)

Group Count Resolution
Translations (Admin/Webhook) 66 Kept master — verified master is a strict superset of 2.1 (0 unique 2.1 key-paths), so nothing lost
Build assets 7 Rebuilt admin + installer from merged source
Code/config 13 Kept master's versions — master already carries the equivalent fixes (TinyMCE FormRequest validation, SVG swatch sanitization, $webhookData, dark-mode), implemented its own way; no security regression

Auto-merged 2.1 improvements master was missing

  • ScopeMiddleware — 2.1's fail-closed check (denies mutating requests with no ACL match) — stronger than master's; brought in.
  • ProductDataGrid — 2.1's Elasticsearch sort-order sanitization — brought in.

Deliberately kept master's

Net new from 2.1

CI workflow updates, CHANGELOG / UPGRADE.md / README doc fixes (incl. the dead UPGRADE-1.0.0-2.0.0.md link → UPGRADE.md), installer test additions, favicon, bundled composer.phar.

Second commit — translation parity fix

The merge surfaced 3 pre-existing parity gaps in master (en_US had keys the 32 locales lacked; absent from 2.1):

  • settings.data-transfer.exports.create.search-categories (Admin)
  • seeders.core.currencies.CAD + installer.index.environment-configuration.dollar (Installer)

Added with natural per-language translations across all 32 locales.

Verification

  • ✅ Pint clean (--test)
  • ✅ unopim:translations:check → 258/258 locales pass
  • ✅ Merged-code security tests pass (15): ProductDataGrid sort-injection, swatch sanitizer, TinyMCE upload validation, family-completeness XSS
  • ⚠️ AdminApi (oauth) test suite fails in this sandbox due to a pre-existing passport key/env issue (oauth/token issues no token). The merge touches zero oauth/passport/AdminApi files — identical setup on both branches — so this is not a regression. Run the API suite in a passport-provisioned env to confirm green.

Reviewer notes

  • Conflict resolution favored master for overlapping code (per the "keep master's features/fixes" requirement); 2.1's net-new and strictly-stronger changes (ScopeMiddleware, ProductDataGrid) still come through.

navneetkumar-pim-webkul and others added 30 commits May 25, 2026 16:54
Audit of the Bouncer middleware route-name ACL check revealed the
same bypass pattern as the roles fix (commit 960b12b) across many
admin sections: only the GET form routes (.create / .edit) were
declared in acl.php, while the actual POST .store and PUT .update
sibling routes were unmapped, so low-privileged admins could submit
forms they could not legitimately view.

Map the missing write-verb routes to the existing permission keys
following the established duplicate-key pattern. Sections covered:

- catalog.products.update
- catalog.categories.store / update
- catalog.category_fields.store / update
- catalog.attributes.store / update
- catalog.attributes.options.store / update / delete / update_sort
- catalog.attribute.groups.store / update
- catalog.families.store / update
- settings.channels.store / update
- settings.currencies.store / update
- settings.locales.update
- settings.data_transfer.imports.store / update / cancel / pause / resume / upload_images_zip
- settings.data_transfer.exports.store / update

Attribute option sub-routes are gated by catalog.attributes.edit
(managing options is part of attribute edit). Import lifecycle
actions (cancel/pause/resume) are gated by data_transfer.imports.execute.

Add Pest regression tests covering each newly mapped route.

Out of scope (separate ticket): configuration.integrations.*,
configuration.store, history.version.delete/restore,
magic_ai.platform.* / prompt.* / system_prompt.*,
catalog.products.bulk-edit.*, catalog.products.check-variant,
catalog.families.completeness.update. These need new permission keys
or product-owner input.
Adds CHANGELOG entry for the security fix landed in 5f84257.
Laravel's url(), asset(), and Vite helpers resolve against the request
Host header by default. Combined with trustProxies(at: '*'), this lets
any client cause UnoPim to render asset URLs (admin <meta base-url>,
Vite <script src>, TinyMCE document_base_url) pointing at an attacker
origin, yielding full frontend takeover.

Layered fix:

1. Pin URL::forceRootUrl + URL::forceScheme to config('app.url') in
   CoreServiceProvider::boot so every url()/asset()/Vite call resolves
   against APP_URL regardless of any Host / X-Forwarded-Host value.

2. Replace url()->to('/') and asset('/') in the admin layout, history
   layout, anonymous layout, and TinyMCE component with
   rtrim(config('app.url'), '/') so the rendered output never reads
   from the request even if a future change drops layer 1.

3. Restrict trustProxies from '*' to env('TRUSTED_PROXIES','127.0.0.1')
   so X-Forwarded-* headers from arbitrary clients are ignored.

4. Enable trustHosts(at: ...) seeded from APP_URL + TRUSTED_HOSTS so
   Symfony returns 400 in non-local environments when the Host header
   is unrecognised.

Documents TRUSTED_PROXIES and TRUSTED_HOSTS in .env.example. Adds a
Pest regression suite that spoofs Host and X-Forwarded-Host headers and
asserts the rendered base-url meta + asset()/url() output stays pinned
to APP_URL.
* fix(installer): preserve user locales/currencies during demo seed  (#401)

* fix(installer): preserve user-selected locales/currencies during demo seeding

* refactor: optimize installer demo seed locale/currency handling

* fix(installer): redirect to install.php when vendor/autoload.php is missing (#400)

* Fix: restored the ui dropdown, and removed the hyphen from placeholder text (#399)

* fix(admin): hide product edit More button when no actions are available (#397)

* Fix: fixed the hide/unhide more button on the product edit page

* Fix: added translation for more text and fixed the test script

* Fix: fixed the dynamic column on the product page (#396)

* fix(webhook): validate URL on save + rename menu to "Webhook" (#398)

* fix(webhook): validate URL with test probe before save and rename menu to singular

* fix(webhook): probe URL before save, rename menu to singular, fix flaky e2e

* fix(webhook): make logs status filter driver-agnostic and per-code

* Add Gravatar fallback for admin avatars (#357)

* Add gravatar-based admin avatar fallback with local proxy

* Fix Blade conflict for Vue image error handler

* fix: address gravatar PR review feedback

* feat(admin): ACL-aware login redirect, datagrid copy/share-edit actions, conditional row actions

- SessionController: redirect post-login to first menu item the admin actually has ACL on (route-level key via app('acl')->roles), with fallback scan of acl config and logout when nothing is accessible
- AdminServiceProvider: expose adminLandingUrl (first authorized menu URL) to views; header logo now uses it instead of hardcoded dashboard route
- Datagrid: support new 'copy' and 'edit-share' action methods, plus per-row action 'condition' callback on Action/DataGrid to hide actions per record
- Datagrid: listen for share-link-changed emitter event to refetch; cleanup on beforeUnmount
- Header: revert avatar to admin->image / image_url path
- Lang: add link-copied / copy-failed strings, prefix select placeholders with "--", drop unused 'more' key

* fix(i18n): add link-copied / copy-failed and drop 'more' orphan in 32 locales

Propagates the en_US additions (admin.components.datagrid.index.link-copied
and copy-failed) and the removal of the unused datagrid 'more' label to all
33 supported locales, restoring Translation Integrity Audit pass.

* test(user): allow null intended URL in open-redirect tests

SessionController no longer stores url.intended when the referer is from a
foreign host (it skips the put instead of defaulting to the dashboard).
A null intended URL is equally safe — login then falls back to the
ACL-aware landing URL — so the test should only enforce that nothing
attacker-controlled is persisted, not that an internal URL is.

* test(e2e): update Hindi-translate test to match current modal markup

The translate modal (translate-action.blade.php) renders step indicators
as numbered circles with "Select Source" / "Select Target" labels — the
literal "Step 1" text was removed in #372 but this assertion was never
updated, causing the test to time out on every push-event run on master.

Switch the visibility check to the "Select Source" label which is the
actual user-visible text when the modal opens.

* Update chat-latest model for temperature not supported

* fix(admin): strip HTML from datagrid cell title tooltip (#403)

* Add Playwright REST API test suite and CI improvements (#413)

* test(api): add Playwright REST API test suite (211 tests)

* fix(test): make API tests run in CI without pre-seeded creds

- oauth.spec.js: lazy-refresh creds after apiToken bootstrap fixture
  (previously credsReady was frozen at file load → always skipped)
- auth-helper.js: fall back ADMIN_EMAIL to ADMIN_USERNAME (the env var
  name used by the existing playwright_test.yml workflow)

* fix(test): make API tests run in CI without pre-seeded creds

* Increase shard count for Playwright tests to 8

* Update Playwright test shards to 10 total

* Reduce Playwright test shards from 10 to 8

* Clean up comments in OAuth test file

Removed comments explaining performance considerations for OAuth tests.

* Address Copilot review comments on API test suite

- schema-validator: drop unsupported keywords from fallback comment;
  cache compiled Ajv validators via WeakMap to avoid per-call recompile
- config.js / .env.example: correct .api-config.json path to
  tests/e2e-pw/ (matches actual resolution)
- utils/api-config.js: add 'use strict' for consistency with siblings
- tests/api/README.md: align parallelism docs with the real
  playwright.config (fullyParallel: false, dynamic worker count)
- playwright.config.js: drop hardcoded "4 shards" from inline comment

* Address Copilot review: clarify validation-error helper and reap category-fields

- expectValidationError: update docstring to match the restricted
  [400, 422, 500] allowlist instead of claiming "any 4xx/5xx", so the
  comment no longer overstates what the helper accepts.
- media-upload spec: track the category-field created in 15.6 and delete
  it in afterAll so repeated runs don't leak cf_media_* rows.

---------

Co-authored-by: kunal kumar <[email protected]>

* Update AiApiClient.php

* Update regex to include 'chat-latest' model

* version2.1

* Update AgentRunner.php

* Update AiApiClient.php

* Update regex to include 'chat-latest' model

* Updated

* Updated chat-latest model for not support temperature

* Updated

* Update AgentRunner.php

* Update AiApiClient.php

* Update LaravelAiAdapter.php

---------

Co-authored-by: Dripar gupta <[email protected]>
Co-authored-by: Prince Kumar Sahni <[email protected]>
Co-authored-by: Johannes Rudolph <[email protected]>
Co-authored-by: Navneet Kumar <[email protected]>
Co-authored-by: Kunal kumar <[email protected]>
Co-authored-by: kunal kumar <[email protected]>
Update SECURITY.md to reflect the 4-branch reality:
- 2.1.x active (current stable)
- 2.0.x security-only until ~90 days after 2.2 ships
- 1.0.x End of Life — v1.0.1 is the final release
- 0.x lines remain EOL

Adds rationale for 1.0 EOL (Laravel 10 EOL Aug 2026, pre-v11 bootstrap,
per-branch backport cost), clarifies the patched-release flow, and
points reporters at GitHub Security Advisories alongside the email
channel.
* ci(docker): resolve version with semver validation and :latest gating

* ci(docker): add QEMU setup and per-image tag computation

* ci(docker): build and push multi-arch (amd64+arm64) web image

* ci(docker): build and push multi-arch (amd64+arm64) queue worker image

* ci(docker): write multi-arch publish summary to GITHUB_STEP_SUMMARY

* ci(docker): gate :minor floating tag, fix MINOR for pre-releases, harden tag input

Review feedback addressed:

- MINOR was derived from VERSION via ${VERSION%.*}, which on tags like
  v2.1.0-beta.2 produced '2.1.0-beta' (last .suffix stripped). Now strip
  the -suffix first via ${VERSION%%-*} so MINOR is always the bare X.Y.
- :minor floating tag was always pushed, so a pre-release like v2.1.0-rc1
  would overwrite the stable :2.1 floating tag — the exact class of bug
  this PR is fixing for :latest. Gate :minor behind is_prerelease == false
  to match :latest gating.
- Move release/input tag from inline \${{ }} into env to avoid shell
  injection via a tag name containing shell metacharacters. Required
  contents:write to exploit, but cheap to harden.

Manual trace verified for v2.1.0, v2.1.0-rc1, v2.1.0-beta.2,
v2.1.0-alpha.1-build.5, v10.20.30.

* ci(docker): smoke-test multi-arch manifests + add queue HEALTHCHECK

Two best-practice additions on top of the multi-arch publish:

1. Smoke-test step after both builds:
   - docker buildx imagetools inspect verifies manifest list shape
     contains both linux/amd64 and linux/arm64 (regex match on raw
     manifest JSON, no false positives).
   - docker run --platform linux/amd64|arm64 boots the image and runs
     'php -v' as a minimal liveness check. Catches QEMU-segfault class
     regressions before users hit them.
   - set -euo pipefail + ::error:: annotations + ::group:: log folding.
   - Tag value passed via env (VERSION) not inline templating, so shell
     metacharacters in a tag cannot inject.

2. HEALTHCHECK in q.Dockerfile:
   - pgrep -f matches either 'artisan queue:work' or 'artisan
     schedule:work' (the same image runs both via overridden entrypoint
     for the scheduler service).
   - Bracket-trick pattern '[a]rtisan ...' keeps pgrep from matching
     its own command line (verified locally).
   - 60s start period gives Laravel boot + initial DB ping time to
     complete before the first probe.

* fix(docker): smoke-test entrypoint override, procps for HEALTHCHECK, workflow concurrency

Fixes the two bugs the previous commit introduced and hardens the
workflow with industry-standard concurrency + timeout controls.

1. Smoke test now overrides ENTRYPOINT:
   web-entrypoint.sh and q-entrypoint.sh require a live database and
   either run migrations or wait for the install lock file. Passing
   'php -v' as CMD reaches the entrypoint, not the PHP binary, so the
   container always exited non-zero before the smoke check could run.
   `--entrypoint php` bypasses the runtime entrypoint and exercises
   only the PHP runtime — sufficient to catch QEMU-segfault / glibc
   regressions, which is the bug class this smoke test exists for.

2. Wrap each docker run in `timeout 90s`:
   prevents a QEMU stall from hanging the whole job until the workflow
   timeout fires.

3. Install procps in q.Dockerfile:
   the HEALTHCHECK uses pgrep, which lives in procps. The php:8.3-cli
   base (debian-slim) does not include procps, so the previous commit
   would have made every queue container report unhealthy on first
   probe.

4. Workflow-level concurrency + per-job timeout:
   - concurrency.group keyed on the release / dispatch tag prevents
     two simultaneous publishes from racing on the same registry tag.
   - timeout-minutes: 90 caps the job below the default 360-minute
     ceiling so a stuck arm64 build fails predictably.

* fix(docker): widen queue HEALTHCHECK start_period to cover install lock wait

q-entrypoint.sh waits up to 300s (SETUP_WAIT_TIMEOUT) for the application
server to finish first-time setup and write storage/unopim.lock before
launching `php artisan queue:work`. With start_period=60s the container
would be marked unhealthy after the first ~150s while still legitimately
waiting for setup. Widen start_period to 360s (300s wait + 60s margin)
so the orchestrator only flags genuine post-startup failures.

Also document the push-then-smoke trade-off in the workflow: multi-arch
builds cannot use load:true (local docker holds only one arch), so the
smoke test runs after push. A failure means the bad image is already
public and requires manual rollback.

* fix(ci): allow hyphens in semver pre-release identifiers (#426 review)

Copilot review on PR #426 flagged the previous regex rejected valid
SemVer pre-release identifiers containing hyphens. Per SemVer 2.0.0 §9,
identifiers comprise ASCII alphanumerics + hyphens (separated by dots),
so tags like v2.1.0-rc-1 and v2.1.0-alpha-build.5 are legitimate
release shapes.

Old pattern: '(-[A-Za-z0-9.]+)?'
New pattern: '(-[0-9A-Za-z.-]+)?'

Trace verified:
  PASS: v2.1.0, v2.1.0-rc1, v2.1.0-beta.2, v2.1.0-rc-1,
        v2.1.0-alpha-build.5, v2.1.0-x-y-z, v10.20.30
  REJECT: vfoo, v2.1, v2.1.0- (trailing hyphen with no suffix)

* fix(ci/docker): address Copilot PR #427 review feedback

Four valid findings, all fixed:

1. HEALTHCHECK ignores operator-overridable SETUP_WAIT_TIMEOUT:
   The previous 360s start_period assumed the default 300s wait. If an
   operator raises SETUP_WAIT_TIMEOUT, the container would be marked
   unhealthy while still legitimately waiting for the install lock,
   triggering restart loops in some orchestrators.

   Rewrite the check so the lock file's presence is part of the
   condition: no lock yet → report healthy (worker still waiting for
   web/fpm setup); lock present → require an active queue:work or
   schedule:work process. start_period drops back to 60s since the
   probe now self-adjusts.

2. workflow_dispatch can build the wrong code:
   For release events github.sha already equals the tag commit, so the
   initial checkout is correct. For workflow_dispatch the initial
   checkout is the dispatched-from ref (master/2.1/whatever), which
   can differ from the `tag` input the operator typed. A `v2.0.5`
   dispatch from master would otherwise publish master's code tagged
   as 2.0.5.

   Add a `Re-checkout tag (workflow_dispatch)` step that runs only on
   dispatch events. It fetches the tag and checks it out in detached
   HEAD before any of the tag-compute or build steps see the
   workspace.

3. + 4. :minor gating comment misleading (web + queue tag steps):
   The code intentionally gates :minor on `is_prerelease=false` only,
   not on `on_default_branch`, so a stable hotfix on a side branch
   (v2.0.5 on the 2.0 line) updates :2.0 without touching :latest.
   The previous comment said "default-branch line", which implied a
   stricter gate than the code actually enforces.

   Rewrite both comments to explain the intent: :minor tracks the
   latest stable on its own release line; only :latest is tied to
   the default branch.
Date bumped to 2026-05-26 (actual release day). Add the four bullet
groups that were folded into the v2.1.1 line after the initial security
tag — installer fixes (#419, #420), styled 405 page (#417), pgsql
demo seeder (#418), MagicAI chat-latest temperature (#416), and the
multi-arch Docker publish (#426). Keeps the two original security
bullets at the top.
GitHub Actions runner is caching a stale v2 tag resolution
(SHA 7c071dfe...) that no longer exists on github.com/shivammathur/setup-php,
so every job using setup-php@v2 fails at 'Set up job' with:

  An action could not be found at the URI
  'https://codeload.github.com/shivammathur/setup-php/tar.gz/7c071dfe...'

Pinning to the latest released tag v2.37.1 (current actual HEAD of v2)
bypasses the stale cache and unblocks Linting / Pest / Playwright /
Translation / Pest-PgSQL workflows until GitHub refreshes the action
resolver.
shivammathur/setup-php releases as '2.37.1' not 'v2.37.1'. Fix the
pin so the action resolver can find it.
…ster)

Private vulnerability reporting is disabled on the repository so the
GHSA 'Report a vulnerability' button does not exist. Keep email
([email protected]) as the single channel.
…lled (#460)

* fix: seal installer to prevent pre-auth admin takeover via AJAX bypass

* fix(installer): seal installer on Docker setup to close pre-auth admin takeover
…ials & make seeders idempotent (#462)

* fix(installer): remove hardcoded admin default credentials and make seeders idempotent (backport #457)

* ci(e2e): pass installer admin creds to seeder and read them in login util so Playwright login matches the seeded admin
…kport) (#468)

* chore(release): v2.1.2 — harden webhook URL handling

* Enforce ACL permission checks on state-changing admin routes
…low (#471)

An empty "${{ }}" inside the Resolve-Version run-block comment is parsed
by GitHub Actions as an expression interpolation. Empty braces fail
validation ("An expression was expected", L50), invalidating the whole
workflow at startup. As a result every release: published event on the
2.1 line silently failed to dispatch, so no Docker image was built or
pushed (e.g. v2.1.2 never reached Docker Hub) and the demo never updated.

Reword the comment to plain text, matching the already-fixed master.
Backports the master fix to the 2.1 default branch so v2.1.3+ releases
auto-publish.
…12 / PHP 8.3 (#466)

The project's composer.json requires laravel/framework ^12.0 and
php ^8.3, but six agent-instruction files (read by Copilot, Kilo
Code, Claude, Cursor, and Codex at session start) still describe
the project as 'Laravel 11' and '.github/copilot-instructions.md'
still requires 'PHP 8.1+'. This causes AI agents to apply Laravel
11 idioms and target the wrong PHP version when generating code.

Files updated:
- AGENTS.md: Laravel 11 → Laravel 12
- code-generation-instructions.md (root + .github/): Laravel 11 → Laravel 12
- code-review-instructions.md     (root + .github/): Laravel 11 → Laravel 12
- .github/copilot-instructions.md:
    * Laravel 11 → Laravel 12, PHP 8.1+ → PHP 8.3+
    * Section 1 was actively misleading: it told agents to hardcode
      the 'wk_' table prefix, which contradicts AGENTS.md
      ('Never hardcode wk_ in table names — it causes wk_wk_ double
      prefix issues') and the actual production code
      (Channel.php → 'channels', CoreConfig.php → 'core_config').
      The section has been rewritten to point at the real
      unprefixed-name convention, with corrected examples.

Co-authored-by: dashitongzhi <[email protected]>
)

* Initial plan

* Clarify DB prefix behavior in Copilot instructions

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Navneet Kumar - Webkul <[email protected]>
* docs: add design spec for Help & Resources menu section

(cherry picked from commit 3c6bc06)

* docs: add implementation plan for Help & Resources menu section

(cherry picked from commit 0847184)

* feat(admin): add reusable global card component

(cherry picked from commit 3e065bd)

* refactor(admin): harden card rel attr + document trusted icon output

(cherry picked from commit 470fe10)

* feat(admin): add help config with sections and cta

(cherry picked from commit 5f71a7d)

* feat(admin): add en_US translations for help section

(cherry picked from commit 4166d0a)

* feat(admin): add help route and controller

(cherry picked from commit 3bec3ad)

* feat(admin): add help page view using card component

(cherry picked from commit a0b710c)

* feat(admin): add help sidebar menu and acl entries

(cherry picked from commit b474fb8)

* i18n(admin): translate help section into all supported locales

(cherry picked from commit cd908fe)

* docs(installer): spec for optional packages + cloud hosting banner

(cherry picked from commit 43d0c8b462d96ba272a4542ac47f59438658c3c3)

* feat(installer): optional add-on packages + cloud hosting banner

Add a multiselect (and --with-packages CSV option) to unopim:install so
operators can pull in official add-ons (DAM, Shopify, Bagisto connectors).
Each is installed after core via composer require + the package's own
artisan installer in a fresh process, with optimize:clear and queue:restart
around it, pinned to the resolved DB connection. Always renders a UnoPim
cloud-hosting promo banner at the end.

* feat(admin): finalize Help & Resources page and card component

Source refinements from 99529f2 (card.blade.php + help/index.blade.php),
without the master-only cleanup deletions / rebuilt assets.

* feat(admin): add dismissible cloud-hosting & version-upgrade promo banners

Carousel promo bar injected at the top of every admin page via the
content.before view event. Cloud-hosting slide always shows; the upgrade
slide appears only when the running version is behind the latest release
(remote Packagist check, cached, fail-silent). Each slide has its own
per-user 'Don't show again' persisted in DB; the upgrade dismissal is
version-scoped so a newer release re-shows it.

Reusable <x-admin::promo-bar> anonymous component + inline v-promo-bar Vue
(auto-rotate, dots, axios dismiss). Strings translated across all 33 locales.

(cherry picked from commit 064617fd9927e614e769d3ba643fb7dd7e4cdfc8)

* fix(admin): correct help service URLs, pin Help menu last, offset layout for promo bar

- Point Services cards at live pages (support-maintenance-services,
  pim-connector-development) and API docs at devdocs.unopim.com/2.1/api.
- Document the Help menu sentinel sort (99999) that keeps it pinned last.
- Offset fixed header/sidebar via :has(#unopim-promo-bar) so the promo bar
  no longer cuts the left menu; make the bar sticky at top.

* build(admin): recompile theme assets with promo bar + help page styles

Rebuild app.css from 2.1 source so the promo-bar/help Tailwind arbitrary
classes (z-[10050], text-[13.5px], max-[820px], h-[30px], etc.) are present.
JS unchanged in spirit — promo bar is registered inline in its blade.

* cleanup extra files

* fix(installer): ask optional-package selection before demo seeding

Demo-data seeding runs Artisan::call() internally, which flips the console
input to non-interactive. Resolving the package multiselect afterwards
silently skipped it when the user chose to seed sample products. Resolve the
selection up front while still interactive; install the packages at the end.

* feat(installer): non-interactive flags --modules and --sampledata

Add --modules (alias for --with-packages) and --sampledata=yes|no (alias for
--with-demo-data) so a fully scripted install needs no prompts. The
interactive 'sample products?' question now yields to either demo-data flag,
so passing one never blocks or double-seeds.

* revert(installer): drop duplicate --modules/--sampledata aliases

Redundant with the existing --with-packages and --with-demo-data flags. Keep
the real fixes: resolve the package selection up front, and skip the
interactive 'sample products?' prompt when --with-demo-data is set or the run
is non-interactive.

* fix(installer): gate prompts on a real TTY, not isInteractive()

GitHub Actions reports input->isInteractive() == true with no STDIN attached,
so the up-front package multiselect prompted and aborted on EOF, failing the
install step (and thus every Pest/Playwright job). Gate the multiselect and
the 'sample products?' prompt on stream_isatty(STDIN) via hasInteractiveTerminal();
headless/CI installs skip them, real terminals still prompt.

* feat(installer): revamp web installer + CLI add-ons, docs, translations

Web installer: admin-themed UI (cloud top bar, vertical stepper, card panels,
language switcher), config-first/install-last flow, live SSE terminal that
streams database → migrate → seed → admin → optional sample data → optional
add-on packages (DAM/Shopify/Bagisto, installed server-side where shell exists).
Adds Elasticsearch setup, DB auto-create (MySQL + pgsql), runtime .env reload,
and shared/FTP-only hosting safeguards. UI polish: requirement/DB grids, bounded
allowed-locale/currency lists, outline Back buttons, browser-origin URL, UTC tz.

Fixes web-context command registration for demo seeding and persists add-on/
sample selections to a transient state file (session was unreliable across the
install). Pins the Help menu/ACL entry last. Adds the new installer keys to all
33 locales, a v2.1.4 changelog entry, and a Cloud Hosting section in the README.

* fix(admin): render flash messages above the promo banner

The promo banner (z-[10050]) overlapped the flash-message stack (z-[10003]),
covering the 'Close' button and breaking catalog E2E specs that dismiss flashes.
Raise the flash group to z-[10060] so notifications sit above the banner.

* fix(admin): keep promo banner in flow so it never overlays UI

* fix(admin): address PR review — guard version JSON, atomic dismissal, bind promo timer

- VersionCheck: bail to fallback when Packagist JSON does not decode to an array
  (avoids array-offset-on-null warnings).
- AdminPromoDismissalRepository: use firstOrCreate so the unique-index dismissal
  write stays idempotent under concurrent requests.
- promo-bar: bind the rotation interval via an arrow fn so `this` is preserved.

* fix(installer): address PR review — server-side promo version, safe .env writes, driver-based db create

- HelpController: derive dismissal version server-side instead of trusting client
- EnvironmentManager: preg_replace_callback so $ in passwords is not a backreference
- DatabaseManager: branch on db driver, not connection name, for pgsql create

* refactor(admin): use Laravel HTTP client instead of curl in VersionCheck

* chore(core): bump version to 2.1.4
dependabot Bot and others added 23 commits June 10, 2026 13:42
Bumps [symfony/routing](https://github.com/symfony/routing) from 7.4.6 to 7.4.13.
- [Release notes](https://github.com/symfony/routing/releases)
- [Changelog](https://github.com/symfony/routing/blob/8.2/CHANGELOG.md)
- [Commits](symfony/routing@v7.4.6...v7.4.13)

---
updated-dependencies:
- dependency-name: symfony/routing
  dependency-version: 7.4.13
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Navneet Kumar - Webkul <[email protected]>
Bumps [symfony/yaml](https://github.com/symfony/yaml) from 7.4.6 to 7.4.13.
- [Release notes](https://github.com/symfony/yaml/releases)
- [Changelog](https://github.com/symfony/yaml/blob/8.2/CHANGELOG.md)
- [Commits](symfony/yaml@v7.4.6...v7.4.13)

---
updated-dependencies:
- dependency-name: symfony/yaml
  dependency-version: 7.4.13
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Navneet Kumar - Webkul <[email protected]>
Removed and re-added the Cloud Hosting section with an image link for better visibility.
…able without permission (#479)

* fix(acl): require platform-edit permission for MagicAI platform update and set-default

* packages/Webkul/refactor: optimize code
…y completeness) (#489)

* fix(xss): escape channel options on family completeness page

* test(e2e): log in over HTTP in global-setup so storageState is authenticated

* refactor: optimize code
Bumps [guzzlehttp/psr7](https://github.com/guzzle/psr7) from 2.9.0 to 2.11.0.
- [Release notes](https://github.com/guzzle/psr7/releases)
- [Changelog](https://github.com/guzzle/psr7/blob/2.11/CHANGELOG.md)
- [Commits](guzzle/psr7@2.9.0...2.11.0)

---
updated-dependencies:
- dependency-name: guzzlehttp/psr7
  dependency-version: 2.11.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…generate routes [2.1] (#494)

* [Security] Fix authorization bypass on MagicAI prompt/system-prompt and AiAgent generate routes

* refactor(acl): enforce ai-agent.generate.process via acl map instead of inline middleware

---------

Co-authored-by: Navneet Kumar - Webkul <[email protected]>
… Too Many Requests when APP_DEBUG=false (#499)

Co-authored-by: Navneet Kumar - Webkul <[email protected]>
* fix(upload): sanitize & validate attribute swatch image uploads via FileStorer

* refactor: optimize code

---------

Co-authored-by: Navneet Kumar - Webkul <[email protected]>
…installer (#491)

Co-authored-by: Navneet Kumar - Webkul <[email protected]>
Co-authored-by: Navneet Kumar - Webkul <[email protected]>
…, dead-file removal (#493)

* chore(github): overhaul issue templates, PR template, contributing guide

- single bug-report form with required environment checklist and
  duplicate-search confirmation; remove legacy markdown duplicate
- fix label case and add title prefixes so labels auto-apply
- issue chooser: add Discussions and documentation links
- CONTRIBUTING: fix dead template links, document conventional
  commits, branch targets, security policy and local CI checks
- PR template: fix malformed HTML comments, actionable checklist

* chore: move AI agent skills to unopim/agent-skills repository

Skills now live in https://github.com/unopim/agent-skills and install
via 'npx skills add unopim/agent-skills'. Remove in-repo skill copies,
agent symlink dirs, the skills-consistency workflow and validator, and
the connector instruction files (moved to the skills repo). Ignore
agent directories so local installs never get committed.

* fix(installer): upgrade script and web-installer composer handling

upgrade.sh:
- backup now includes storage/ user data (media); previously a restore
  lost all uploads. Excludes only deps, caches, logs, debugbar
- copy step includes dotfiles (.env.example, .gitignore were dropped)
- anchored .env parsing; passwords with '=' or quotes no longer break
  the dump; credentials passed via MYSQL_PWD/PGPASSWORD env vars
- PostgreSQL support via pg_dump based on DB_CONNECTION
- rm -f the temp dump so a failed dump cannot abort the run (set -e)
- drop dead UPGRADE_TO_VERSION stub

install.php: COMPOSER_HOME now points to a writable directory
(storage/composer) instead of the phar file path.

InstallerController: probe bundled bin/composer/composer.phar in
resolveComposerBinary(); paths extracted to composerProbePaths() with
tests. Stabilise installer tests with DatabaseTransactions so runs no
longer pollute the dev database.

Docs: consolidate UPGRADE.md (remove stale per-release impact lists and
dead link), drop superseded per-version upgrade guides, fix README
upgrade link, add pg_dump backup instructions.

* chore: remove dead files, update bundled composer, add favicon

- remove unused leftovers: public/forge, patches.lock.json (plugin not
  installed), config/horizon.php and config/sitemap.php (packages not
  installed), broken bin/codecept symlink, placeholder DataGrid test
  and its now-empty phpunit suite entries
- update bundled composer.phar 2.8.3 -> 2.10.1
- add public/favicon.ico (browsers request it unconditionally)
- changelog: draft v2.1.5 entry

---------

Co-authored-by: Dripar gupta <[email protected]>
- Core::VERSION 2.1.4 -> 2.1.5
- Remove unused version field from private package.json
…503)

* fixed: Confirm before demo-data seeding overwrites existing data

* Fixed:Confirm and guard demo-data seeding to prevent data loss

* refactor: shorten code comments

---------

Co-authored-by: Navneet Kumar - Webkul <[email protected]>
Bumps [laravel/framework](https://github.com/laravel/framework) from 12.55.1 to 12.61.1.
- [Release notes](https://github.com/laravel/framework/releases)
- [Changelog](https://github.com/laravel/framework/blob/13.x/CHANGELOG.md)
- [Commits](laravel/framework@v12.55.1...v12.61.1)

---
updated-dependencies:
- dependency-name: laravel/framework
  dependency-version: 12.61.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [phpseclib/phpseclib](https://github.com/phpseclib/phpseclib) from 3.0.52 to 3.0.55.
- [Release notes](https://github.com/phpseclib/phpseclib/releases)
- [Changelog](https://github.com/phpseclib/phpseclib/blob/master/CHANGELOG.md)
- [Commits](phpseclib/phpseclib@3.0.52...3.0.55)

---
updated-dependencies:
- dependency-name: phpseclib/phpseclib
  dependency-version: 3.0.55
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Navneet Kumar - Webkul <[email protected]>
…tion (#514)

* Feat: added the default selection value on installer cli with search

* Chore: class name rename

---------

Co-authored-by: Navneet Kumar - Webkul <[email protected]>
Brings remaining 2.1-only changes into master while preserving master's own
features and fixes. Conflicts resolved as follows:

- Code (TinyMCE/swatch/dark-mode/webhook/installer): kept master's versions —
  master already carries the equivalent fixes (validation, SVG sanitization,
  $webhookData) implemented its own way; no security regression.
- ScopeMiddleware / ProductDataGrid: took the stronger 2.1 hardening
  (fail-closed mutating-request check; sort-order sanitization) that master
  lacked — auto-merged.
- Translations (Admin/Webhook, 66 files): kept master (verified strict
  superset of 2.1 — zero 2.1-only key paths, so no loss).
- Core::VERSION and package.json version: kept master's (release identity is
  not a merge side effect).
- phpunit.xml: dropped empty "DataGrid Unit Test" suite (ExampleTest removed
  in #523 cleanup).
- Admin + installer build assets rebuilt from merged source.

Net new from 2.1: CI workflow updates, CHANGELOG/UPGRADE/README doc updates
(incl. UPGRADE.md link fix), installer test additions, favicon, composer.phar.

Pre-existing master translation parity gaps (search-categories, currencies.CAD,
environment-configuration.dollar) are unchanged by this merge and fixed in a
follow-up commit.
Resolve pre-existing translation parity gaps where en_US carried keys the
other locales lacked (surfaced during the 2.1 convergence; present on master
independently of it):

- Admin:     settings.data-transfer.exports.create.search-categories
- Installer: seeders.core.currencies.CAD
- Installer: installer.index.environment-configuration.dollar

Added with natural per-language translations (not English copies) to all 32
non-English locales. en_US untouched; en_AU/en_GB/en_NZ use English text.

unopim:translations:check: 258/258 locales pass. Pint clean.
Copilot AI review requested due to automatic review settings June 26, 2026 14:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@navneetkumar-pim-webkul
navneetkumar-pim-webkul merged commit 2bf05de into master Jun 26, 2026
21 of 31 checks passed
@navneetkumar-pim-webkul
navneetkumar-pim-webkul deleted the sync/merge-2.1-into-master branch June 26, 2026 15:01
navneetkumar-pim-webkul added a commit that referenced this pull request Jun 26, 2026
…trollerTest (#526)

The 2.1 convergence merge (#525) brought in 2.1's InstallerControllerTest
(which asserts a `composerProbePaths()` method and a bundled
`bin/composer/composer.phar` probe) but kept master's InstallerController,
which inlined the probe list and lacked that method — causing 2 CI Pest
failures.

Extract the probe list into composerProbePaths() (adding the bundled
bin/composer/composer.phar path) and have resolveComposerBinary() iterate it,
matching the test. Pure refactor — runtime behaviour unchanged except the
extra bundled-phar probe.

InstallerControllerTest: 7/7 pass. Pint clean.
kunal-kumar-dev pushed a commit to kunal-kumar-dev/unopim that referenced this pull request Jul 6, 2026
…trollerTest (unopim#526)

The 2.1 convergence merge (unopim#525) brought in 2.1's InstallerControllerTest
(which asserts a `composerProbePaths()` method and a bundled
`bin/composer/composer.phar` probe) but kept master's InstallerController,
which inlined the probe list and lacked that method — causing 2 CI Pest
failures.

Extract the probe list into composerProbePaths() (adding the bundled
bin/composer/composer.phar path) and have resolveComposerBinary() iterate it,
matching the test. Pure refactor — runtime behaviour unchanged except the
extra bundled-phar probe.

InstallerControllerTest: 7/7 pass. Pint clean.
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.

7 participants