Skip to content

Merge 5.0.1 into main - #1742

Merged
yenienserrano merged 14 commits into
mainfrom
merge-5.0.1-into-main
Nov 6, 2026
Merged

yenienserrano merged 14 commits into
mainfrom
merge-5.0.1-into-main

Conversation

@yenienserrano

Copy link
Copy Markdown
Member

Merge 5.0.1 into main.

Also aligns main with 5.0.1: removes resolve-credentials.sh and the old parts of build-packages.sh and the deb postrm that the 5.0 package rework (#1678) replaced.

Related to #1730

yenienserrano and others added 14 commits August 21, 2026 13:02
* Report skipped bumps in the repository bumper workflow (#1492)

Improve repository bumper error handling

* Recalculate flyout position when the sidecar is opened (#1503)

* Adapt flyout position in relation to the sidecar

* Add changelog

* Change resizable button emphasis style from :focus to :active (#1508)

* fix(sidecar): change resizable button emphasis style from :focus to :active

Update the .sidecar-resizableButton CSS to emphasize the "grab" icon
on :active instead of :focus, matching the intended interaction
feedback when dragging the resizer.

Closes wazuh/wazuh-dashboard-plugins#8989

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): remove leftover native focus outline on resizable button

The resizable button programmatically calls .focus() on every click,
so after removing the custom :focus emphasis in favor of :active, the
browser's default focus outline was left showing as an unstyled
colored border until focus moved elsewhere. Suppress it for
mouse/touch interaction while keeping it for keyboard users via
:focus-visible.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): opt out resizable button from the global focus-ring animation

The resizable button programmatically calls .focus() on every click,
which triggered OSD's global brute-force focus-ring animation
(:focus:not([class^="eui"]):not(.osd-resetFocusState) in _base.scss)
since the button isn't an EUI component. That showed as a lingering
colored border after dragging, independent from the button's own
:active styling. Opt out via the "osd-resetFocusState" class, which is
the mechanism _base.scss already documents for components with
hand-crafted focus states, instead of fighting the rule's
!important/specificity locally. Supersedes the previous outline:none
attempt, which didn't target the actual animation.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(sidecar): allow configuring the resizable button className

Add an optional className prop to ResizableButton, and forward it from
a new classNameButton option on OverlaySidecarOpenOptions/Sidecar, so
callers of overlays.sidecar.open() can style/opt-out the resizer
button (e.g. pass "osd-resetFocusState" to drop the global focus-ring
animation) without hardcoding it in the component.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Change top bar health-check icon (#1505)

* feat: update health check indicator

* Change top bar health-check icon to a pulse shown only when attention is needed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(core): use kebab-case for sidecar docked-mode CSS variable

Rename --osdSidecarSize to --osd-sidecar-size and switch attribute
selectors to double quotes to satisfy the repo's stylelint rules
(custom-property-pattern, string-quotes), registering sidecar.scss
in the global selectors allowlist for its .euiFlyout references.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* chore: use constant

* Rework health-check popover

* Rework health-check popover

* List failing health checks in the nav-button popover

Show the enabled non-green checks as an EuiHealth list in the health-check
popover, labelled by the check name and with the error surfaced in a tooltip.
Use the shared mapTaskStatusToHealthColor helper and TASK.RUN_RESULT constants
instead of magic strings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Fix popover closes when clicking inside

* Close popover after navigating to the health check

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Bump 5.0.0 branch (#1513)

feat: bump 5.0.0

* Fix RPM changelog entry order causing build failure (#1516)

Fix RPM changelog entry order for 5.0.0

The 5.0.0 changelog entry was placed out of descending chronological
order, causing rpmbuild to fail while parsing %changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1517)

Remove unnecessary debhelper install-time dependency (#1484)

fix: remove unnecessary debhelper install-time dependency

debhelper is only required to build the .deb package (declared under
Build-Depends in dev-tools/build-packages/deb/debian/control), not to
install a pre-built one. Remove it from the apt-get install steps used
to test package install/upgrade.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Rodrigo López <37187963+rodrigofez@users.noreply.github.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
* Report skipped bumps in the repository bumper workflow (#1492)

Improve repository bumper error handling

* Recalculate flyout position when the sidecar is opened (#1503)

* Adapt flyout position in relation to the sidecar

* Add changelog

* Change resizable button emphasis style from :focus to :active (#1508)

* fix(sidecar): change resizable button emphasis style from :focus to :active

Update the .sidecar-resizableButton CSS to emphasize the "grab" icon
on :active instead of :focus, matching the intended interaction
feedback when dragging the resizer.

Closes wazuh/wazuh-dashboard-plugins#8989

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): remove leftover native focus outline on resizable button

The resizable button programmatically calls .focus() on every click,
so after removing the custom :focus emphasis in favor of :active, the
browser's default focus outline was left showing as an unstyled
colored border until focus moved elsewhere. Suppress it for
mouse/touch interaction while keeping it for keyboard users via
:focus-visible.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): opt out resizable button from the global focus-ring animation

The resizable button programmatically calls .focus() on every click,
which triggered OSD's global brute-force focus-ring animation
(:focus:not([class^="eui"]):not(.osd-resetFocusState) in _base.scss)
since the button isn't an EUI component. That showed as a lingering
colored border after dragging, independent from the button's own
:active styling. Opt out via the "osd-resetFocusState" class, which is
the mechanism _base.scss already documents for components with
hand-crafted focus states, instead of fighting the rule's
!important/specificity locally. Supersedes the previous outline:none
attempt, which didn't target the actual animation.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(sidecar): allow configuring the resizable button className

Add an optional className prop to ResizableButton, and forward it from
a new classNameButton option on OverlaySidecarOpenOptions/Sidecar, so
callers of overlays.sidecar.open() can style/opt-out the resizer
button (e.g. pass "osd-resetFocusState" to drop the global focus-ring
animation) without hardcoding it in the component.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Change top bar health-check icon (#1505)

* feat: update health check indicator

* Change top bar health-check icon to a pulse shown only when attention is needed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(core): use kebab-case for sidecar docked-mode CSS variable

Rename --osdSidecarSize to --osd-sidecar-size and switch attribute
selectors to double quotes to satisfy the repo's stylelint rules
(custom-property-pattern, string-quotes), registering sidecar.scss
in the global selectors allowlist for its .euiFlyout references.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* chore: use constant

* Rework health-check popover

* Rework health-check popover

* List failing health checks in the nav-button popover

Show the enabled non-green checks as an EuiHealth list in the health-check
popover, labelled by the check name and with the error surfaced in a tooltip.
Use the shared mapTaskStatusToHealthColor helper and TASK.RUN_RESULT constants
instead of magic strings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Fix popover closes when clicking inside

* Close popover after navigating to the health check

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Bump 5.0.0 branch (#1513)

feat: bump 5.0.0

* Fix RPM changelog entry order causing build failure (#1516)

Fix RPM changelog entry order for 5.0.0

The 5.0.0 changelog entry was placed out of descending chronological
order, causing rpmbuild to fail while parsing %changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1517)

Remove unnecessary debhelper install-time dependency (#1484)

fix: remove unnecessary debhelper install-time dependency

debhelper is only required to build the .deb package (declared under
Build-Depends in dev-tools/build-packages/deb/debian/control), not to
install a pre-built one. Remove it from the apt-get install steps used
to test package install/upgrade.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1537)

Merge 4.14.9 into 5.0.0: no changes (verified 2026-08-28)

* fix: remove inert opensearch_security.cookie.ttl setting (#1534)

The dashboard config declares opensearch_security.cookie.ttl, but the
security plugin never reads it: only opensearch_security.session.ttl
governs session/cookie expiry. Shipping the setting misleads operators
into believing it bounds the cookie lifetime.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Rodrigo López <37187963+rodrigofez@users.noreply.github.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
* Report skipped bumps in the repository bumper workflow (#1492)

Improve repository bumper error handling

* Recalculate flyout position when the sidecar is opened (#1503)

* Adapt flyout position in relation to the sidecar

* Add changelog

* Change resizable button emphasis style from :focus to :active (#1508)

* fix(sidecar): change resizable button emphasis style from :focus to :active

Update the .sidecar-resizableButton CSS to emphasize the "grab" icon
on :active instead of :focus, matching the intended interaction
feedback when dragging the resizer.

Closes wazuh/wazuh-dashboard-plugins#8989

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): remove leftover native focus outline on resizable button

The resizable button programmatically calls .focus() on every click,
so after removing the custom :focus emphasis in favor of :active, the
browser's default focus outline was left showing as an unstyled
colored border until focus moved elsewhere. Suppress it for
mouse/touch interaction while keeping it for keyboard users via
:focus-visible.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): opt out resizable button from the global focus-ring animation

The resizable button programmatically calls .focus() on every click,
which triggered OSD's global brute-force focus-ring animation
(:focus:not([class^="eui"]):not(.osd-resetFocusState) in _base.scss)
since the button isn't an EUI component. That showed as a lingering
colored border after dragging, independent from the button's own
:active styling. Opt out via the "osd-resetFocusState" class, which is
the mechanism _base.scss already documents for components with
hand-crafted focus states, instead of fighting the rule's
!important/specificity locally. Supersedes the previous outline:none
attempt, which didn't target the actual animation.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(sidecar): allow configuring the resizable button className

Add an optional className prop to ResizableButton, and forward it from
a new classNameButton option on OverlaySidecarOpenOptions/Sidecar, so
callers of overlays.sidecar.open() can style/opt-out the resizer
button (e.g. pass "osd-resetFocusState" to drop the global focus-ring
animation) without hardcoding it in the component.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Change top bar health-check icon (#1505)

* feat: update health check indicator

* Change top bar health-check icon to a pulse shown only when attention is needed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(core): use kebab-case for sidecar docked-mode CSS variable

Rename --osdSidecarSize to --osd-sidecar-size and switch attribute
selectors to double quotes to satisfy the repo's stylelint rules
(custom-property-pattern, string-quotes), registering sidecar.scss
in the global selectors allowlist for its .euiFlyout references.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* chore: use constant

* Rework health-check popover

* Rework health-check popover

* List failing health checks in the nav-button popover

Show the enabled non-green checks as an EuiHealth list in the health-check
popover, labelled by the check name and with the error surfaced in a tooltip.
Use the shared mapTaskStatusToHealthColor helper and TASK.RUN_RESULT constants
instead of magic strings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Fix popover closes when clicking inside

* Close popover after navigating to the health check

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Bump 5.0.0 branch (#1513)

feat: bump 5.0.0

* Fix RPM changelog entry order causing build failure (#1516)

Fix RPM changelog entry order for 5.0.0

The 5.0.0 changelog entry was placed out of descending chronological
order, causing rpmbuild to fail while parsing %changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1517)

Remove unnecessary debhelper install-time dependency (#1484)

fix: remove unnecessary debhelper install-time dependency

debhelper is only required to build the .deb package (declared under
Build-Depends in dev-tools/build-packages/deb/debian/control), not to
install a pre-built one. Remove it from the apt-get install steps used
to test package install/upgrade.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1537)

Merge 4.14.9 into 5.0.0: no changes (verified 2026-08-28)

* fix: remove inert opensearch_security.cookie.ttl setting (#1534)

The dashboard config declares opensearch_security.cookie.ttl, but the
security plugin never reads it: only opensearch_security.session.ttl
governs session/cookie expiry. Shipping the setting misleads operators
into believing it bounds the cookie lifetime.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Bump 5.0.0 branch (#1545)

feat: bump 5.0.0

* Revert bump 5.0.0 branch (#1546)

feat: revert 5.0.0 references

* Fix changelog not in descending chronological order (#1548)

* fix: keep RPM changelog entries in descending date order on re-bump (#1549)

Re-bumping an existing version updated its date in place instead of
repositioning it, so a newer date could end up below older entries and
rpmbuild rejected the spec (%changelog not in descending chronological
order). The entry is now removed and reinserted at the position
matching its date.

Also fixes date/sed portability on macOS (BSD date/sed vs GNU), and
makes an invalid date abort the script instead of writing the error
text into the changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Bump 5.0.0 branch (#1551)

feat: bump 5.0.0

* Review the 5.0.0 changelog (#1556)

* docs(changelog): review the 5.0.0 entries

Removed the open redirect fix entry (#1285) and the pre install script
check entry (#1328, #1365).

Reordered the sections to Added, Changed, Removed, Fixed, and qualified
the two wazuh-dashboard-plugins references so they no longer read as
wazuh-dashboard issues.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): reference issues instead of pull requests

Each entry now links the issue the pull request closed, so the reference
carries the description and the discussion instead of just the diff.

Where an entry listed several references that resolve the same issue, it
collapses to that one; where they resolve different issues, the entry
keeps the main one and the rest are attached to it as sub-issues on
GitHub, following the shape of wazuh-dashboard-plugins#8789.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): merge the health check service and app entries

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* docs(changelog): point the health check entry at its parent issue

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1563)

Merge 4.14.8 into 4.14.9 (#1562)

Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x
# Conflicts:
#	dev-tools/build-dev-image/README.md
#	dev-tools/build-dev-image/build-multiarch.sh
#	dev-tools/build-dev-image/install-plugins.sh
#	dev-tools/build-dev-image/plugins
#	dev-tools/build-dev-image/warmup-opensearch_dashboards.yml
#	dev-tools/build-dev-image/warmup-optimizer.sh
#	dev-tools/build-dev-image/wzd.dockerfile

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Rodrigo López <37187963+rodrigofez@users.noreply.github.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
* Report skipped bumps in the repository bumper workflow (#1492)

Improve repository bumper error handling

* Recalculate flyout position when the sidecar is opened (#1503)

* Adapt flyout position in relation to the sidecar

* Add changelog

* Change resizable button emphasis style from :focus to :active (#1508)

* fix(sidecar): change resizable button emphasis style from :focus to :active

Update the .sidecar-resizableButton CSS to emphasize the "grab" icon
on :active instead of :focus, matching the intended interaction
feedback when dragging the resizer.

Closes wazuh/wazuh-dashboard-plugins#8989

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): remove leftover native focus outline on resizable button

The resizable button programmatically calls .focus() on every click,
so after removing the custom :focus emphasis in favor of :active, the
browser's default focus outline was left showing as an unstyled
colored border until focus moved elsewhere. Suppress it for
mouse/touch interaction while keeping it for keyboard users via
:focus-visible.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): opt out resizable button from the global focus-ring animation

The resizable button programmatically calls .focus() on every click,
which triggered OSD's global brute-force focus-ring animation
(:focus:not([class^="eui"]):not(.osd-resetFocusState) in _base.scss)
since the button isn't an EUI component. That showed as a lingering
colored border after dragging, independent from the button's own
:active styling. Opt out via the "osd-resetFocusState" class, which is
the mechanism _base.scss already documents for components with
hand-crafted focus states, instead of fighting the rule's
!important/specificity locally. Supersedes the previous outline:none
attempt, which didn't target the actual animation.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(sidecar): allow configuring the resizable button className

Add an optional className prop to ResizableButton, and forward it from
a new classNameButton option on OverlaySidecarOpenOptions/Sidecar, so
callers of overlays.sidecar.open() can style/opt-out the resizer
button (e.g. pass "osd-resetFocusState" to drop the global focus-ring
animation) without hardcoding it in the component.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Change top bar health-check icon (#1505)

* feat: update health check indicator

* Change top bar health-check icon to a pulse shown only when attention is needed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(core): use kebab-case for sidecar docked-mode CSS variable

Rename --osdSidecarSize to --osd-sidecar-size and switch attribute
selectors to double quotes to satisfy the repo's stylelint rules
(custom-property-pattern, string-quotes), registering sidecar.scss
in the global selectors allowlist for its .euiFlyout references.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* chore: use constant

* Rework health-check popover

* Rework health-check popover

* List failing health checks in the nav-button popover

Show the enabled non-green checks as an EuiHealth list in the health-check
popover, labelled by the check name and with the error surfaced in a tooltip.
Use the shared mapTaskStatusToHealthColor helper and TASK.RUN_RESULT constants
instead of magic strings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Fix popover closes when clicking inside

* Close popover after navigating to the health check

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Bump 5.0.0 branch (#1513)

feat: bump 5.0.0

* Fix RPM changelog entry order causing build failure (#1516)

Fix RPM changelog entry order for 5.0.0

The 5.0.0 changelog entry was placed out of descending chronological
order, causing rpmbuild to fail while parsing %changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1517)

Remove unnecessary debhelper install-time dependency (#1484)

fix: remove unnecessary debhelper install-time dependency

debhelper is only required to build the .deb package (declared under
Build-Depends in dev-tools/build-packages/deb/debian/control), not to
install a pre-built one. Remove it from the apt-get install steps used
to test package install/upgrade.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1537)

Merge 4.14.9 into 5.0.0: no changes (verified 2026-08-28)

* fix: remove inert opensearch_security.cookie.ttl setting (#1534)

The dashboard config declares opensearch_security.cookie.ttl, but the
security plugin never reads it: only opensearch_security.session.ttl
governs session/cookie expiry. Shipping the setting misleads operators
into believing it bounds the cookie lifetime.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Bump 5.0.0 branch (#1545)

feat: bump 5.0.0

* Revert bump 5.0.0 branch (#1546)

feat: revert 5.0.0 references

* Fix changelog not in descending chronological order (#1548)

* fix: keep RPM changelog entries in descending date order on re-bump (#1549)

Re-bumping an existing version updated its date in place instead of
repositioning it, so a newer date could end up below older entries and
rpmbuild rejected the spec (%changelog not in descending chronological
order). The entry is now removed and reinserted at the position
matching its date.

Also fixes date/sed portability on macOS (BSD date/sed vs GNU), and
makes an invalid date abort the script instead of writing the error
text into the changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Bump 5.0.0 branch (#1551)

feat: bump 5.0.0

* Review the 5.0.0 changelog (#1556)

* docs(changelog): review the 5.0.0 entries

Removed the open redirect fix entry (#1285) and the pre install script
check entry (#1328, #1365).

Reordered the sections to Added, Changed, Removed, Fixed, and qualified
the two wazuh-dashboard-plugins references so they no longer read as
wazuh-dashboard issues.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): reference issues instead of pull requests

Each entry now links the issue the pull request closed, so the reference
carries the description and the discussion instead of just the diff.

Where an entry listed several references that resolve the same issue, it
collapses to that one; where they resolve different issues, the entry
keeps the main one and the rest are attached to it as sub-issues on
GitHub, following the shape of wazuh-dashboard-plugins#8789.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): merge the health check service and app entries

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* docs(changelog): point the health check entry at its parent issue

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1563)

Merge 4.14.8 into 4.14.9 (#1562)

Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x
# Conflicts:
#	dev-tools/build-dev-image/README.md
#	dev-tools/build-dev-image/build-multiarch.sh
#	dev-tools/build-dev-image/install-plugins.sh
#	dev-tools/build-dev-image/plugins
#	dev-tools/build-dev-image/warmup-opensearch_dashboards.yml
#	dev-tools/build-dev-image/warmup-optimizer.sh
#	dev-tools/build-dev-image/wzd.dockerfile

* Bump 5.0.0 branch (#1567)

feat: bump 5.0.0

* Bump 5.0.0 branch (#1571)

feat: bump 5.0.0

* Fix empty error message in dashboard save failure toast (#1573)

The danger toast shown when saving a dashboard fails interpolated
savedDashboard.message, a property that does not exist on the saved
object instance, so the message always rendered as
"Dashboard 'X' was not saved. Error:" with nothing after "Error:".

Use the caught error's message instead.

Closes #1568

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Show the root cause of the failure in the error toast full error modal (#1574)

The See the full error modal built its copyable block from caused_by, which
can hold a failure raised while the response itself was being built rather
than the failure that made the request fail: querying a field that is not
searchable reported a null_pointer_exception about reducePhase.aggregations
instead of the query_shard_exception the backend reports under root_cause.

The reason of the root cause is now shown inside the danger callout, under
the message of the error, and is stripped of URLs, IP addresses and
filesystem paths. The copyable block keeps the content it had on 5.0.0,
the client stack trace included.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Merge 4.14.9 into 5.0.0 (#1581)

Merge 4.14.8 into 4.14.9 (#1580)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Reorder rpm changelog

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Rodrigo López <37187963+rodrigofez@users.noreply.github.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
* Report skipped bumps in the repository bumper workflow (#1492)

Improve repository bumper error handling

* Recalculate flyout position when the sidecar is opened (#1503)

* Adapt flyout position in relation to the sidecar

* Add changelog

* Change resizable button emphasis style from :focus to :active (#1508)

* fix(sidecar): change resizable button emphasis style from :focus to :active

Update the .sidecar-resizableButton CSS to emphasize the "grab" icon
on :active instead of :focus, matching the intended interaction
feedback when dragging the resizer.

Closes wazuh/wazuh-dashboard-plugins#8989

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): remove leftover native focus outline on resizable button

The resizable button programmatically calls .focus() on every click,
so after removing the custom :focus emphasis in favor of :active, the
browser's default focus outline was left showing as an unstyled
colored border until focus moved elsewhere. Suppress it for
mouse/touch interaction while keeping it for keyboard users via
:focus-visible.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): opt out resizable button from the global focus-ring animation

The resizable button programmatically calls .focus() on every click,
which triggered OSD's global brute-force focus-ring animation
(:focus:not([class^="eui"]):not(.osd-resetFocusState) in _base.scss)
since the button isn't an EUI component. That showed as a lingering
colored border after dragging, independent from the button's own
:active styling. Opt out via the "osd-resetFocusState" class, which is
the mechanism _base.scss already documents for components with
hand-crafted focus states, instead of fighting the rule's
!important/specificity locally. Supersedes the previous outline:none
attempt, which didn't target the actual animation.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(sidecar): allow configuring the resizable button className

Add an optional className prop to ResizableButton, and forward it from
a new classNameButton option on OverlaySidecarOpenOptions/Sidecar, so
callers of overlays.sidecar.open() can style/opt-out the resizer
button (e.g. pass "osd-resetFocusState" to drop the global focus-ring
animation) without hardcoding it in the component.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Change top bar health-check icon (#1505)

* feat: update health check indicator

* Change top bar health-check icon to a pulse shown only when attention is needed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(core): use kebab-case for sidecar docked-mode CSS variable

Rename --osdSidecarSize to --osd-sidecar-size and switch attribute
selectors to double quotes to satisfy the repo's stylelint rules
(custom-property-pattern, string-quotes), registering sidecar.scss
in the global selectors allowlist for its .euiFlyout references.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* chore: use constant

* Rework health-check popover

* Rework health-check popover

* List failing health checks in the nav-button popover

Show the enabled non-green checks as an EuiHealth list in the health-check
popover, labelled by the check name and with the error surfaced in a tooltip.
Use the shared mapTaskStatusToHealthColor helper and TASK.RUN_RESULT constants
instead of magic strings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Fix popover closes when clicking inside

* Close popover after navigating to the health check

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Bump 5.0.0 branch (#1513)

feat: bump 5.0.0

* Fix RPM changelog entry order causing build failure (#1516)

Fix RPM changelog entry order for 5.0.0

The 5.0.0 changelog entry was placed out of descending chronological
order, causing rpmbuild to fail while parsing %changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1517)

Remove unnecessary debhelper install-time dependency (#1484)

fix: remove unnecessary debhelper install-time dependency

debhelper is only required to build the .deb package (declared under
Build-Depends in dev-tools/build-packages/deb/debian/control), not to
install a pre-built one. Remove it from the apt-get install steps used
to test package install/upgrade.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1537)

Merge 4.14.9 into 5.0.0: no changes (verified 2026-08-28)

* fix: remove inert opensearch_security.cookie.ttl setting (#1534)

The dashboard config declares opensearch_security.cookie.ttl, but the
security plugin never reads it: only opensearch_security.session.ttl
governs session/cookie expiry. Shipping the setting misleads operators
into believing it bounds the cookie lifetime.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Bump 5.0.0 branch (#1545)

feat: bump 5.0.0

* Revert bump 5.0.0 branch (#1546)

feat: revert 5.0.0 references

* Fix changelog not in descending chronological order (#1548)

* fix: keep RPM changelog entries in descending date order on re-bump (#1549)

Re-bumping an existing version updated its date in place instead of
repositioning it, so a newer date could end up below older entries and
rpmbuild rejected the spec (%changelog not in descending chronological
order). The entry is now removed and reinserted at the position
matching its date.

Also fixes date/sed portability on macOS (BSD date/sed vs GNU), and
makes an invalid date abort the script instead of writing the error
text into the changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Bump 5.0.0 branch (#1551)

feat: bump 5.0.0

* Review the 5.0.0 changelog (#1556)

* docs(changelog): review the 5.0.0 entries

Removed the open redirect fix entry (#1285) and the pre install script
check entry (#1328, #1365).

Reordered the sections to Added, Changed, Removed, Fixed, and qualified
the two wazuh-dashboard-plugins references so they no longer read as
wazuh-dashboard issues.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): reference issues instead of pull requests

Each entry now links the issue the pull request closed, so the reference
carries the description and the discussion instead of just the diff.

Where an entry listed several references that resolve the same issue, it
collapses to that one; where they resolve different issues, the entry
keeps the main one and the rest are attached to it as sub-issues on
GitHub, following the shape of wazuh-dashboard-plugins#8789.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): merge the health check service and app entries

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* docs(changelog): point the health check entry at its parent issue

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1563)

Merge 4.14.8 into 4.14.9 (#1562)

Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x
# Conflicts:
#	dev-tools/build-dev-image/README.md
#	dev-tools/build-dev-image/build-multiarch.sh
#	dev-tools/build-dev-image/install-plugins.sh
#	dev-tools/build-dev-image/plugins
#	dev-tools/build-dev-image/warmup-opensearch_dashboards.yml
#	dev-tools/build-dev-image/warmup-optimizer.sh
#	dev-tools/build-dev-image/wzd.dockerfile

* Bump 5.0.0 branch (#1567)

feat: bump 5.0.0

* Bump 5.0.0 branch (#1571)

feat: bump 5.0.0

* Fix empty error message in dashboard save failure toast (#1573)

The danger toast shown when saving a dashboard fails interpolated
savedDashboard.message, a property that does not exist on the saved
object instance, so the message always rendered as
"Dashboard 'X' was not saved. Error:" with nothing after "Error:".

Use the caught error's message instead.

Closes #1568

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Show the root cause of the failure in the error toast full error modal (#1574)

The See the full error modal built its copyable block from caused_by, which
can hold a failure raised while the response itself was being built rather
than the failure that made the request fail: querying a field that is not
searchable reported a null_pointer_exception about reducePhase.aggregations
instead of the query_shard_exception the backend reports under root_cause.

The reason of the root cause is now shown inside the danger callout, under
the message of the error, and is stripped of URLs, IP addresses and
filesystem paths. The copyable block keeps the content it had on 5.0.0,
the client stack trace included.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Merge 4.14.9 into 5.0.0 (#1581)

Merge 4.14.8 into 4.14.9 (#1580)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Reorder rpm changelog

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>

* Merge 4.14.10 into 5.0.0 (#1602)

* Bump 4.14.10 branch (#1589)

feat: bump 4.14.10

* Merge 4.14.9 into 4.14.10 (#1601)

Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Remove duplicated 4.14.8 entry from the RPM changelog

The 4.14.8 bump (#1597) changed the date of the existing 4.14.8 entry
from Sep 16 to Sep 23. That change reached 4.14.9, 4.14.10 and 5.0.0,
but not 5.0.1, so merging 5.0.0 into 5.0.1 brought both dates in as two
separate entries. Keep the Sep 23 one, matching the other branches.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Rodrigo López <37187963+rodrigofez@users.noreply.github.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
* Report skipped bumps in the repository bumper workflow (#1492)

Improve repository bumper error handling

* Recalculate flyout position when the sidecar is opened (#1503)

* Adapt flyout position in relation to the sidecar

* Add changelog

* Change resizable button emphasis style from :focus to :active (#1508)

* fix(sidecar): change resizable button emphasis style from :focus to :active

Update the .sidecar-resizableButton CSS to emphasize the "grab" icon
on :active instead of :focus, matching the intended interaction
feedback when dragging the resizer.

Closes wazuh/wazuh-dashboard-plugins#8989

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): remove leftover native focus outline on resizable button

The resizable button programmatically calls .focus() on every click,
so after removing the custom :focus emphasis in favor of :active, the
browser's default focus outline was left showing as an unstyled
colored border until focus moved elsewhere. Suppress it for
mouse/touch interaction while keeping it for keyboard users via
:focus-visible.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): opt out resizable button from the global focus-ring animation

The resizable button programmatically calls .focus() on every click,
which triggered OSD's global brute-force focus-ring animation
(:focus:not([class^="eui"]):not(.osd-resetFocusState) in _base.scss)
since the button isn't an EUI component. That showed as a lingering
colored border after dragging, independent from the button's own
:active styling. Opt out via the "osd-resetFocusState" class, which is
the mechanism _base.scss already documents for components with
hand-crafted focus states, instead of fighting the rule's
!important/specificity locally. Supersedes the previous outline:none
attempt, which didn't target the actual animation.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(sidecar): allow configuring the resizable button className

Add an optional className prop to ResizableButton, and forward it from
a new classNameButton option on OverlaySidecarOpenOptions/Sidecar, so
callers of overlays.sidecar.open() can style/opt-out the resizer
button (e.g. pass "osd-resetFocusState" to drop the global focus-ring
animation) without hardcoding it in the component.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Change top bar health-check icon (#1505)

* feat: update health check indicator

* Change top bar health-check icon to a pulse shown only when attention is needed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(core): use kebab-case for sidecar docked-mode CSS variable

Rename --osdSidecarSize to --osd-sidecar-size and switch attribute
selectors to double quotes to satisfy the repo's stylelint rules
(custom-property-pattern, string-quotes), registering sidecar.scss
in the global selectors allowlist for its .euiFlyout references.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* chore: use constant

* Rework health-check popover

* Rework health-check popover

* List failing health checks in the nav-button popover

Show the enabled non-green checks as an EuiHealth list in the health-check
popover, labelled by the check name and with the error surfaced in a tooltip.
Use the shared mapTaskStatusToHealthColor helper and TASK.RUN_RESULT constants
instead of magic strings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Fix popover closes when clicking inside

* Close popover after navigating to the health check

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Bump 5.0.0 branch (#1513)

feat: bump 5.0.0

* Fix RPM changelog entry order causing build failure (#1516)

Fix RPM changelog entry order for 5.0.0

The 5.0.0 changelog entry was placed out of descending chronological
order, causing rpmbuild to fail while parsing %changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1517)

Remove unnecessary debhelper install-time dependency (#1484)

fix: remove unnecessary debhelper install-time dependency

debhelper is only required to build the .deb package (declared under
Build-Depends in dev-tools/build-packages/deb/debian/control), not to
install a pre-built one. Remove it from the apt-get install steps used
to test package install/upgrade.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1537)

Merge 4.14.9 into 5.0.0: no changes (verified 2026-08-28)

* fix: remove inert opensearch_security.cookie.ttl setting (#1534)

The dashboard config declares opensearch_security.cookie.ttl, but the
security plugin never reads it: only opensearch_security.session.ttl
governs session/cookie expiry. Shipping the setting misleads operators
into believing it bounds the cookie lifetime.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Bump 5.0.0 branch (#1545)

feat: bump 5.0.0

* Revert bump 5.0.0 branch (#1546)

feat: revert 5.0.0 references

* Fix changelog not in descending chronological order (#1548)

* fix: keep RPM changelog entries in descending date order on re-bump (#1549)

Re-bumping an existing version updated its date in place instead of
repositioning it, so a newer date could end up below older entries and
rpmbuild rejected the spec (%changelog not in descending chronological
order). The entry is now removed and reinserted at the position
matching its date.

Also fixes date/sed portability on macOS (BSD date/sed vs GNU), and
makes an invalid date abort the script instead of writing the error
text into the changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Bump 5.0.0 branch (#1551)

feat: bump 5.0.0

* Review the 5.0.0 changelog (#1556)

* docs(changelog): review the 5.0.0 entries

Removed the open redirect fix entry (#1285) and the pre install script
check entry (#1328, #1365).

Reordered the sections to Added, Changed, Removed, Fixed, and qualified
the two wazuh-dashboard-plugins references so they no longer read as
wazuh-dashboard issues.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): reference issues instead of pull requests

Each entry now links the issue the pull request closed, so the reference
carries the description and the discussion instead of just the diff.

Where an entry listed several references that resolve the same issue, it
collapses to that one; where they resolve different issues, the entry
keeps the main one and the rest are attached to it as sub-issues on
GitHub, following the shape of wazuh-dashboard-plugins#8789.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): merge the health check service and app entries

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* docs(changelog): point the health check entry at its parent issue

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1563)

Merge 4.14.8 into 4.14.9 (#1562)

Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x
# Conflicts:
#	dev-tools/build-dev-image/README.md
#	dev-tools/build-dev-image/build-multiarch.sh
#	dev-tools/build-dev-image/install-plugins.sh
#	dev-tools/build-dev-image/plugins
#	dev-tools/build-dev-image/warmup-opensearch_dashboards.yml
#	dev-tools/build-dev-image/warmup-optimizer.sh
#	dev-tools/build-dev-image/wzd.dockerfile

* Bump 5.0.0 branch (#1567)

feat: bump 5.0.0

* Bump 5.0.0 branch (#1571)

feat: bump 5.0.0

* Fix empty error message in dashboard save failure toast (#1573)

The danger toast shown when saving a dashboard fails interpolated
savedDashboard.message, a property that does not exist on the saved
object instance, so the message always rendered as
"Dashboard 'X' was not saved. Error:" with nothing after "Error:".

Use the caught error's message instead.

Closes #1568

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Show the root cause of the failure in the error toast full error modal (#1574)

The See the full error modal built its copyable block from caused_by, which
can hold a failure raised while the response itself was being built rather
than the failure that made the request fail: querying a field that is not
searchable reported a null_pointer_exception about reducePhase.aggregations
instead of the query_shard_exception the backend reports under root_cause.

The reason of the root cause is now shown inside the danger callout, under
the message of the error, and is stripped of URLs, IP addresses and
filesystem paths. The copyable block keeps the content it had on 5.0.0,
the client stack trace included.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Merge 4.14.9 into 5.0.0 (#1581)

Merge 4.14.8 into 4.14.9 (#1580)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Reorder rpm changelog

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>

* Merge 4.14.10 into 5.0.0 (#1602)

* Bump 4.14.10 branch (#1589)

feat: bump 4.14.10

* Merge 4.14.9 into 4.14.10 (#1601)

Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Let a health check task report red, and show that red in the overall status (#1595)

* feat: Add TaskResult so health check tasks report their own result status

A health check task could only resolve or throw, and the registration-time
`critical` flag decided whether a throw became yellow or red. Because that same
flag also decides whether a failure blocks startup, a task had no way to report
red without holding the dashboard behind the "server is not ready yet" screen.

A task may now resolve a branded `TaskResult` and pick its own result status.
`critical` is untouched and goes on deciding whether a red result blocks
startup, so the new reachable combination is a non-critical red: visible,
without blocking.

The result is branded with a registry symbol rather than detected structurally.
An existing task already resolves `{ status: 'ok' }` as its data, so a
structural guard would reinterpret plain task data as a status and drop the
payload.

Tasks that resolve or throw are unaffected. No existing task changes.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* fix: Respect the check own result when computing the health check overall status

computeOverallStatus decided the overall status only from the critical flag,
so a check reporting red landed on the header as yellow. Every check registered
by the Wazuh plugins is non critical, which capped the indicator at yellow and
made red unreachable.

The aggregation now returns red for any finished check whose result is red,
keeps escalating a non green critical check to red, and returns yellow for any
other non green result.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* fix: Type the health check task error property as string or null

`public error = null` made TypeScript infer the literal type `null`, so
assigning a TaskResult message broke `tsc -b tsconfig.refs.json` and the CI
bootstrap. The catch branch got away with the same assignment because a catch
binding is `any`.

`ITask['error']` is already `string | null`, which is what the property held
all along.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* docs: Drop the redundant health check changelog entry

The overall status aggregation was not fixing a defect users could reach. In
5.0.0 the only assignment of a red result sits behind `if (this.critical)`, so
a non-critical red does not exist and the old aggregation was equivalent to the
new one. That state is created by this branch, so the behaviour belongs to the
Added entry rather than to a separate Fixed one.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* change: Require health check tasks to return a task result

A task could resolve any value, which the platform stored as data and marked
green, or resolve a branded TaskResult. Two return shapes for one outcome, and
the plain one gave a task no way to say anything but green.

`TaskDefinition.run` now returns a TaskResult. A value that is not branded is
rejected at runtime as well, because the type does not reach a task written in
JavaScript, and a silent gray result would be worse than a loud failure.

Throwing is unchanged and stays the path for the unexpected.

BREAKING CHANGE: every registered task must return taskResult.ok, warning or
error. The tasks in wazuh-dashboard-plugins migrate alongside this.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* docs: Update the health check README for the task result contract

The README documented the semantics this branch inverts. It stated in six
places that the result color encodes criticality: red meant a critical failure
and yellow a non-critical one, and the summary went red only for a critical
task. That held while the only path to red was a throw from a critical task.

It also described the summary with the startup blocking rule. Those are two
aggregations answering different questions, and only one of them changed, so
they are now documented apart.

The registration example returned nothing, which the new contract rejects.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Break word to prevent overflow

* change: Provide the result constructors in the health check task context

A task had to build its TaskResult itself, and core exported no constructor to
build one with. wazuh-dashboard-plugins answered that by hand-rolling a mirror
of the contract, relying on Symbol.for to resolve to the same brand. A required
contract nobody can import is a contract everybody copies.

The context a task already receives now carries the constructors, so a task
reports a result without importing anything. TaskRunContext replaces the `any`
the run parameter used to be, and the contract types are exported by name,
closing the TODO that kept them private.

Suggested by @Desvelao in review.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* refactor: Remove the unused health check ITask from the common types

It declared `run` as returning a generic `Promise<Result>`, which contradicts
both the task contract and the `ITask` the server defines. Nothing imported it,
in this repo or in wazuh-dashboard-plugins.

The name still exists in the server task types, which is the one implemented.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* change: Export the health check task contract from the server entry point

A plugin registering a check could not import TaskDefinition, TaskRunContext,
TaskResult or TaskResultFactory from src/core/server, so it redeclared them.
They are exported there now.

The manager annotates the context it passes, so the compiler checks that the
injected constructors reach the task.

The README interface block now matches the type: run receives a TaskRunContext,
critical is optional, and there is no index signature for extra fields.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

---------

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* feat(core): configurable version, help menu links, and an About page (#1609)

* feat(core): add configurable version, help menu links, and an About page

- opensearchDashboards.branding.applicationVersion overrides the version
  shown in the About page and the persistent help-menu badge; falls back
  to the real build version.
- opensearchDashboards.branding.helpMenuLinks overrides the help menu's
  Documentation/Slack/GitHub/Google Group list (replaces it entirely when
  set); each entry supports an optional darkModeIcon.
- New src/plugins/about core plugin hosts the About page (moved out of
  wazuh-dashboard-plugins), with its own about.communityLinks setting
  (same {label, link, icon, darkModeIcon} shape, hides the Community
  panel when set to an empty list), registered under the same "Dashboard
  management" category/position the page had before the move.
- Synced the legacy Joi config schema (src/legacy/server/config/schema.js)
  with the new branding.* keys to fix a boot-time validation error.
- Registered the new "about" i18n namespace in src/.i18nrc.json.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): use the Wazuh copyright header on new about plugin files

The new files added for the about plugin and help_menu type used the
"Copyright OpenSearch Contributors" header template, reserved for
OpenSearch-authored files. These are wholly new, Wazuh-original files, so
per this fork's own convention (.eslintrc.js OSD_WAZUH header, "For new
files created by Wazuh Contributors") they should use "Copyright Wazuh"
instead.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs(changelog): add entries for the about plugin and branding settings

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): hide all help menu links when helpMenuLinks is empty

Treat opensearchDashboards.branding.helpMenuLinks as configured whenever it
is set, so an empty list renders no links instead of falling back to the
built-in ones, matching about.communityLinks and the documented behavior.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): register the About app in the all nav group

Add the About app to DEFAULT_NAV_GROUPS.all under the Dashboard
management category so it stays visible once the new navigation is
enabled. Previously it reached the nav group through the main plugin's
registerWazuhNavLinks, which no longer lists it after the move.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* fix(core): set the About page breadcrumb and document title

The About app never set its breadcrumb or document title, so the header
kept showing the previous app's breadcrumb (e.g. "Overview") and the tab
title stayed "Wazuh". Set both to "About" when the app mounts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Merge 4.14.10 into 5.0.0 (#1616)

Merge 4.14.9 into 4.14.10 (#1615)

* Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------




* Merge 4.14.8 into 4.14.9 (#1614)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

* Bump 4.14.8 branch (#1612)

feat: bump 4.14.8

---------




---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Rodrigo López <37187963+rodrigofez@users.noreply.github.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Diego García <82405377+Ripdiegozz@users.noreply.github.com>
* Report skipped bumps in the repository bumper workflow (#1492)

Improve repository bumper error handling

* Recalculate flyout position when the sidecar is opened (#1503)

* Adapt flyout position in relation to the sidecar

* Add changelog

* Change resizable button emphasis style from :focus to :active (#1508)

* fix(sidecar): change resizable button emphasis style from :focus to :active

Update the .sidecar-resizableButton CSS to emphasize the "grab" icon
on :active instead of :focus, matching the intended interaction
feedback when dragging the resizer.

Closes https://github.com/wazuh/wazuh-dashboard-plugins/issues/8989

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): remove leftover native focus outline on resizable button

The resizable button programmatically calls .focus() on every click,
so after removing the custom :focus emphasis in favor of :active, the
browser's default focus outline was left showing as an unstyled
colored border until focus moved elsewhere. Suppress it for
mouse/touch interaction while keeping it for keyboard users via
:focus-visible.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): opt out resizable button from the global focus-ring animation

The resizable button programmatically calls .focus() on every click,
which triggered OSD's global brute-force focus-ring animation
(:focus:not([class^="eui"]):not(.osd-resetFocusState) in _base.scss)
since the button isn't an EUI component. That showed as a lingering
colored border after dragging, independent from the button's own
:active styling. Opt out via the "osd-resetFocusState" class, which is
the mechanism _base.scss already documents for components with
hand-crafted focus states, instead of fighting the rule's
!important/specificity locally. Supersedes the previous outline:none
attempt, which didn't target the actual animation.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(sidecar): allow configuring the resizable button className

Add an optional className prop to ResizableButton, and forward it from
a new classNameButton option on OverlaySidecarOpenOptions/Sidecar, so
callers of overlays.sidecar.open() can style/opt-out the resizer
button (e.g. pass "osd-resetFocusState" to drop the global focus-ring
animation) without hardcoding it in the component.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Change top bar health-check icon (#1505)

* feat: update health check indicator

* Change top bar health-check icon to a pulse shown only when attention is needed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(core): use kebab-case for sidecar docked-mode CSS variable

Rename --osdSidecarSize to --osd-sidecar-size and switch attribute
selectors to double quotes to satisfy the repo's stylelint rules
(custom-property-pattern, string-quotes), registering sidecar.scss
in the global selectors allowlist for its .euiFlyout references.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* chore: use constant

* Rework health-check popover

* Rework health-check popover

* List failing health checks in the nav-button popover

Show the enabled non-green checks as an EuiHealth list in the health-check
popover, labelled by the check name and with the error surfaced in a tooltip.
Use the shared mapTaskStatusToHealthColor helper and TASK.RUN_RESULT constants
instead of magic strings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Fix popover closes when clicking inside

* Close popover after navigating to the health check

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Bump 5.0.0 branch (#1513)

feat: bump 5.0.0

* Fix RPM changelog entry order causing build failure (#1516)

Fix RPM changelog entry order for 5.0.0

The 5.0.0 changelog entry was placed out of descending chronological
order, causing rpmbuild to fail while parsing %changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1517)

Remove unnecessary debhelper install-time dependency (#1484)

fix: remove unnecessary debhelper install-time dependency

debhelper is only required to build the .deb package (declared under
Build-Depends in dev-tools/build-packages/deb/debian/control), not to
install a pre-built one. Remove it from the apt-get install steps used
to test package install/upgrade.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1537)

Merge 4.14.9 into 5.0.0: no changes (verified 2026-08-28)

* fix: remove inert opensearch_security.cookie.ttl setting (#1534)

The dashboard config declares opensearch_security.cookie.ttl, but the
security plugin never reads it: only opensearch_security.session.ttl
governs session/cookie expiry. Shipping the setting misleads operators
into believing it bounds the cookie lifetime.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Bump 5.0.0 branch (#1545)

feat: bump 5.0.0

* Revert bump 5.0.0 branch (#1546)

feat: revert 5.0.0 references

* Fix changelog not in descending chronological order (#1548)

* fix: keep RPM changelog entries in descending date order on re-bump (#1549)

Re-bumping an existing version updated its date in place instead of
repositioning it, so a newer date could end up below older entries and
rpmbuild rejected the spec (%changelog not in descending chronological
order). The entry is now removed and reinserted at the position
matching its date.

Also fixes date/sed portability on macOS (BSD date/sed vs GNU), and
makes an invalid date abort the script instead of writing the error
text into the changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Bump 5.0.0 branch (#1551)

feat: bump 5.0.0

* Review the 5.0.0 changelog (#1556)

* docs(changelog): review the 5.0.0 entries

Removed the open redirect fix entry (#1285) and the pre install script
check entry (#1328, #1365).

Reordered the sections to Added, Changed, Removed, Fixed, and qualified
the two wazuh-dashboard-plugins references so they no longer read as
wazuh-dashboard issues.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): reference issues instead of pull requests

Each entry now links the issue the pull request closed, so the reference
carries the description and the discussion instead of just the diff.

Where an entry listed several references that resolve the same issue, it
collapses to that one; where they resolve different issues, the entry
keeps the main one and the rest are attached to it as sub-issues on
GitHub, following the shape of wazuh-dashboard-plugins#8789.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): merge the health check service and app entries

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* docs(changelog): point the health check entry at its parent issue

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1563)

Merge 4.14.8 into 4.14.9 (#1562)

Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x
# Conflicts:
#	dev-tools/build-dev-image/README.md
#	dev-tools/build-dev-image/build-multiarch.sh
#	dev-tools/build-dev-image/install-plugins.sh
#	dev-tools/build-dev-image/plugins
#	dev-tools/build-dev-image/warmup-opensearch_dashboards.yml
#	dev-tools/build-dev-image/warmup-optimizer.sh
#	dev-tools/build-dev-image/wzd.dockerfile

* Bump 5.0.0 branch (#1567)

feat: bump 5.0.0

* Bump 5.0.0 branch (#1571)

feat: bump 5.0.0

* Fix empty error message in dashboard save failure toast (#1573)

The danger toast shown when saving a dashboard fails interpolated
savedDashboard.message, a property that does not exist on the saved
object instance, so the message always rendered as
"Dashboard 'X' was not saved. Error:" with nothing after "Error:".

Use the caught error's message instead.

Closes #1568

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Show the root cause of the failure in the error toast full error modal (#1574)

The See the full error modal built its copyable block from caused_by, which
can hold a failure raised while the response itself was being built rather
than the failure that made the request fail: querying a field that is not
searchable reported a null_pointer_exception about reducePhase.aggregations
instead of the query_shard_exception the backend reports under root_cause.

The reason of the root cause is now shown inside the danger callout, under
the message of the error, and is stripped of URLs, IP addresses and
filesystem paths. The copyable block keeps the content it had on 5.0.0,
the client stack trace included.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Merge 4.14.9 into 5.0.0 (#1581)

Merge 4.14.8 into 4.14.9 (#1580)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Reorder rpm changelog

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>

* Merge 4.14.10 into 5.0.0 (#1602)

* Bump 4.14.10 branch (#1589)

feat: bump 4.14.10

* Merge 4.14.9 into 4.14.10 (#1601)

Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Let a health check task report red, and show that red in the overall status (#1595)

* feat: Add TaskResult so health check tasks report their own result status

A health check task could only resolve or throw, and the registration-time
`critical` flag decided whether a throw became yellow or red. Because that same
flag also decides whether a failure blocks startup, a task had no way to report
red without holding the dashboard behind the "server is not ready yet" screen.

A task may now resolve a branded `TaskResult` and pick its own result status.
`critical` is untouched and goes on deciding whether a red result blocks
startup, so the new reachable combination is a non-critical red: visible,
without blocking.

The result is branded with a registry symbol rather than detected structurally.
An existing task already resolves `{ status: 'ok' }` as its data, so a
structural guard would reinterpret plain task data as a status and drop the
payload.

Tasks that resolve or throw are unaffected. No existing task changes.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* fix: Respect the check own result when computing the health check overall status

computeOverallStatus decided the overall status only from the critical flag,
so a check reporting red landed on the header as yellow. Every check registered
by the Wazuh plugins is non critical, which capped the indicator at yellow and
made red unreachable.

The aggregation now returns red for any finished check whose result is red,
keeps escalating a non green critical check to red, and returns yellow for any
other non green result.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* fix: Type the health check task error property as string or null

`public error = null` made TypeScript infer the literal type `null`, so
assigning a TaskResult message broke `tsc -b tsconfig.refs.json` and the CI
bootstrap. The catch branch got away with the same assignment because a catch
binding is `any`.

`ITask['error']` is already `string | null`, which is what the property held
all along.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* docs: Drop the redundant health check changelog entry

The overall status aggregation was not fixing a defect users could reach. In
5.0.0 the only assignment of a red result sits behind `if (this.critical)`, so
a non-critical red does not exist and the old aggregation was equivalent to the
new one. That state is created by this branch, so the behaviour belongs to the
Added entry rather than to a separate Fixed one.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* change: Require health check tasks to return a task result

A task could resolve any value, which the platform stored as data and marked
green, or resolve a branded TaskResult. Two return shapes for one outcome, and
the plain one gave a task no way to say anything but green.

`TaskDefinition.run` now returns a TaskResult. A value that is not branded is
rejected at runtime as well, because the type does not reach a task written in
JavaScript, and a silent gray result would be worse than a loud failure.

Throwing is unchanged and stays the path for the unexpected.

BREAKING CHANGE: every registered task must return taskResult.ok, warning or
error. The tasks in wazuh-dashboard-plugins migrate alongside this.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* docs: Update the health check README for the task result contract

The README documented the semantics this branch inverts. It stated in six
places that the result color encodes criticality: red meant a critical failure
and yellow a non-critical one, and the summary went red only for a critical
task. That held while the only path to red was a throw from a critical task.

It also described the summary with the startup blocking rule. Those are two
aggregations answering different questions, and only one of them changed, so
they are now documented apart.

The registration example returned nothing, which the new contract rejects.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Break word to prevent overflow

* change: Provide the result constructors in the health check task context

A task had to build its TaskResult itself, and core exported no constructor to
build one with. wazuh-dashboard-plugins answered that by hand-rolling a mirror
of the contract, relying on Symbol.for to resolve to the same brand. A required
contract nobody can import is a contract everybody copies.

The context a task already receives now carries the constructors, so a task
reports a result without importing anything. TaskRunContext replaces the `any`
the run parameter used to be, and the contract types are exported by name,
closing the TODO that kept them private.

Suggested by @Desvelao in review.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* refactor: Remove the unused health check ITask from the common types

It declared `run` as returning a generic `Promise<Result>`, which contradicts
both the task contract and the `ITask` the server defines. Nothing imported it,
in this repo or in wazuh-dashboard-plugins.

The name still exists in the server task types, which is the one implemented.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* change: Export the health check task contract from the server entry point

A plugin registering a check could not import TaskDefinition, TaskRunContext,
TaskResult or TaskResultFactory from src/core/server, so it redeclared them.
They are exported there now.

The manager annotates the context it passes, so the compiler checks that the
injected constructors reach the task.

The README interface block now matches the type: run receives a TaskRunContext,
critical is optional, and there is no index signature for extra fields.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

---------

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* feat(core): configurable version, help menu links, and an About page (#1609)

* feat(core): add configurable version, help menu links, and an About page

- opensearchDashboards.branding.applicationVersion overrides the version
  shown in the About page and the persistent help-menu badge; falls back
  to the real build version.
- opensearchDashboards.branding.helpMenuLinks overrides the help menu's
  Documentation/Slack/GitHub/Google Group list (replaces it entirely when
  set); each entry supports an optional darkModeIcon.
- New src/plugins/about core plugin hosts the About page (moved out of
  wazuh-dashboard-plugins), with its own about.communityLinks setting
  (same {label, link, icon, darkModeIcon} shape, hides the Community
  panel when set to an empty list), registered under the same "Dashboard
  management" category/position the page had before the move.
- Synced the legacy Joi config schema (src/legacy/server/config/schema.js)
  with the new branding.* keys to fix a boot-time validation error.
- Registered the new "about" i18n namespace in src/.i18nrc.json.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): use the Wazuh copyright header on new about plugin files

The new files added for the about plugin and help_menu type used the
"Copyright OpenSearch Contributors" header template, reserved for
OpenSearch-authored files. These are wholly new, Wazuh-original files, so
per this fork's own convention (.eslintrc.js OSD_WAZUH header, "For new
files created by Wazuh Contributors") they should use "Copyright Wazuh"
instead.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs(changelog): add entries for the about plugin and branding settings

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): hide all help menu links when helpMenuLinks is empty

Treat opensearchDashboards.branding.helpMenuLinks as configured whenever it
is set, so an empty list renders no links instead of falling back to the
built-in ones, matching about.communityLinks and the documented behavior.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): register the About app in the all nav group

Add the About app to DEFAULT_NAV_GROUPS.all under the Dashboard
management category so it stays visible once the new navigation is
enabled. Previously it reached the nav group through the main plugin's
registerWazuhNavLinks, which no longer lists it after the move.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* fix(core): set the About page breadcrumb and document title

The About app never set its breadcrumb or document title, so the header
kept showing the previous app's breadcrumb (e.g. "Overview") and the tab
title stayed "Wazuh". Set both to "About" when the app mounts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Merge 4.14.10 into 5.0.0 (#1616)

Merge 4.14.9 into 4.14.10 (#1615)

* Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------




* Merge 4.14.8 into 4.14.9 (#1614)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

* Bump 4.14.8 branch (#1612)

feat: bump 4.14.8

---------




---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Resolve dashboard credentials at install and start (#1613)

* feat(packages): resolve dashboard credentials at install and start

Replace the hardcoded kibanaserver keystore pair and the plaintext
wazuh-wui password with the shared resolve-credentials script, run from
postinst/%post and from the unit's ExecStartPre=+. The script is
downloaded and checksum-verified at build time. Purge removes /etc/wazuh
only when no other Wazuh central component remains.

Closes #1594

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): ship the credentials resolver in the repo

Replace the build-time download of resolve-credentials with a script
maintained in this repository, adapted from the manager's resolver.
Only the shared wazuh-credentials.sh library is still downloaded at
build time, from wazuh-installation-assistant, into lib/.

The resolver takes --install, --upgrade, --prestart and --clear. The
maintainer scripts, the systemd unit and the SysV init script call it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): honour credentials set in the dashboard config

Treat opensearch.password and wazuh_core.hosts.default.password set in
opensearch_dashboards.yml as resolved, so the resolver neither refuses
the start nor writes keystore entries that would override the yml.
Never write opensearch.username over a user set in the yml, and skip
the wazuh-wui entry when the yml defines no default host.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): generate the AI assistant key in the resolver

Move the wazuh_ai_assistant.encryptionKey generation out of postinst
and %post into resolve-credentials. It is generated on --install and
--prestart when neither the keystore nor opensearch_dashboards.yml has
it, never on --upgrade, and never replaced. A generation failure only
warns. --clear now removes it too, so an image does not share one key
across containers.

The resolver already creates the keystore, so the maintainer scripts no
longer do.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): pick the credentials library ref from the build

Try an ordered list of wazuh-installation-assistant refs (override, tag
being built, branch being built, version branch, version tag) instead of
a single ref. A tag build only tries its tag.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): supply credentials before starting the service in CI

The unit now runs resolve-credentials --prestart, which refuses to start
while the kibanaserver and wazuh-wui passwords are unresolved. The DEB
install test started the service on a clean install with no credentials,
so the start failed.

Assert the refusal first, then write test credentials to
/etc/wazuh/credentials.env and start the service. Dump the unit journal
on failure.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): issue the dashboard TLS certificates from the shared CA

On a fresh install, resolve-credentials now issues dashboard.pem and
dashboard-key.pem, and installs root-ca.pem, into
/etc/wazuh-dashboard/certs from the shared Wazuh root CA (/etc/wazuh/ca).
The CA is created through the shared credentials library when no
component has created it yet, and reused otherwise.

An existing complete pair is kept, a partial pair is refused, and an
anchor-only CA cannot issue, so the operator is told to stage a pair.
--upgrade and --prestart never touch the certificates; --clear removes
them together with a CA minted on this host. Files are staged in a
root-only directory and published with ln -T, and each step is logged
with public data only.

The packages now depend on openssl (and diffutils and util-linux on
RPM), which the issuance and the shared library need.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs(packages): reference the manager's certificate issuance

Point the dashboard certificate step and its README to the manager's
issue and PR it mirrors: wazuh/wazuh#39554 and wazuh/wazuh#39571.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* revert: reference the manager's certificate issuance

This reverts commit e9bde535c6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): supply credentials before starting the service in RPM CI

The unit runs resolve-credentials --prestart, which refuses to start while
the kibanaserver and wazuh-wui passwords are unresolved. The RPM install
test still started the service on a clean install with no credentials, so
the start failed (run 36148424354).

Move the inline SSH test into rpm-test-install-uninstall.sh, mirroring the
DEB test: check the issued certificates, assert the refusal, write test
credentials to /etc/wazuh/credentials.env, start the service and dump the
unit journal on failure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): only reject passwords the keystore would not store verbatim

resolve-credentials validated the consumed kibanaserver and wazuh-wui
passwords against the shared password policy. That policy is fetched
unpinned from wazuh-installation-assistant and has since gained a symbol
requirement, so the CI test passwords were rejected and the service did
not start (run 36389268794). The dashboard's own message already
described an older version of the rule.

The indexer and the manager own these passwords and enforce the policy.
The dashboard now checks only what is its own concern: keystore add
trims the value and stores it JSON.parse'd, so reject any value it would
not store verbatim (JSON numbers, booleans, quoted strings, arrays,
objects, surrounding whitespace). The check repeats add.js with the
bundled Node.

Add a negative case to the DEB and RPM install tests asserting that a
JSON number is reported as INVALID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): add a VM test matrix for install and start

vm-test-matrix.sh runs 21 cases against a built .deb or .rpm on a
disposable VM: fresh install, credentials from credentials.env, the
environment and the yml, invalid values, a refused credentials file,
shared CA reuse, anchor-only CA, operator and partial certificate pairs,
custom SANs, --clear, removal, reinstall and, with --previous, upgrades.
The host is wiped after every case and a summary is printed.
--clean-only wipes the host without running a case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): cover install orders with the manager and indexer

Rename --package and --previous to --dashboard and --dashboard-previous,
and add --manager and --indexer. Dashboard-only cases are now D01-D21;
the new F01-F08 cases need both sibling packages and run only when they
are given.

F01-F06 install the indexer, the manager and the dashboard in every
order and check after each step that the dashboard resolves exactly
what credentials.env holds, names what it lacks, refuses to start until
both keys are resolved, and reuses or mints the shared CA. F07 purges
the dashboard with the siblings still installed; F08 reinstalls it. The
siblings' own start and CA are recorded as [INFO].

Cleanup purges wazuh-manager and wazuh-indexer too when their packages
are given, or with --force.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): let the service group read the shared credentials library

At startup OSD's i18n loader globs */.i18nrc.json under the installation
root, which lists every top-level directory. lib/ was root:root 0750, so
the wazuh-dashboard user got EACCES on scandir and the server exited with
a fatal error.

Keep lib/ and wazuh-credentials.sh owned by root, so the service user
still cannot modify what ExecStartPre=+ sources as root, but give them
the wazuh-dashboard group (0750 / 0640) so the loader can list the
directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): read the keystore before grepping it in CI

`keystore list | grep -q` under `pipefail` failed when grep closed the
pipe on the first match and the keystore CLI hit EPIPE, reporting the AI
assistant key as missing although it was present (RPM aarch64).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Check Prettier only on the lines a change writes (#1608)

* fix(ci): check Prettier only on the lines a change writes

The check runs over every file a change touches. Most of this repository
comes from OpenSearch Dashboards, which never ran Prettier over its own
tree, so changing two lines in a file that was never formatted demands a
reformat of the whole file. On wazuh/wazuh-dashboard-alerting#148 that was
318 lines of rewriting to land 400 lines of work.

No configuration fixes this. Sweeping nine Prettier versions from 1.19.1 to
3.6.2 and every single-option change against upstream's own `.prettierrc`
leaves a floor of 73 of 670 source files failing. There is nothing to align
to.

Rewriting those files is what costs us. Each one diverges from its
counterpart on the other version branches, so the next upward merge or
cherry-pick conflicts, and the next OpenSearch migration replays a larger
Wazuh delta onto the new upstream tree.

So a change answers for the lines it writes and nothing else. A file it adds
is checked in full; a line it did not touch is not checked.

`scripts/prettier-check-changed.js` compares what the change wrote against
what Prettier wants and reports the overlap. `--fix` corrects those lines
and leaves the rest of the file alone. A merge branch passes the branch
being merged as a second base, so lines that exist in either parent are not
the merge's own. The pre-commit hook returns early during a merge,
cherry-pick, revert or rebase, where it was blocking
`git cherry-pick --continue` during the scheduled merges.

Backtested over 43 merged pull requests across the six repositories it
spares 28 of 29 files, with no false positives.

Refs wazuh/wazuh-dashboard#1605

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(ci): compare against the merge base and follow renames

Three problems found in review.

The check diffed against the tip of the base branch. When the base moves
ahead after a pull request branches off, that diff also reports the base's
own later commits, in reverse, and blames them on the change. A pull request
that adds one line was asked to reformat a line the base had already fixed.
Resolve each base with `git merge-base <ref> HEAD` instead, which is what
GitHub uses for "Files changed", so the check and the diff a reviewer reads
agree. The workflow needs the shared history for that, so the checkout takes
`fetch-depth: 0`.

A renamed file was checked in full. Git cannot pair a rename when the diff
receives only the new path, so it reported the file as added. Pass both paths.
The rename map was also built against the first base alone, so with two bases
the second lookup missed and the file looked new again; build one map per
base. Any upward merge carrying a rename hit this.

The `--fix` hint named `scripts/`, which is wrong in `wazuh-dashboard` where
the script lives in `dev-tools/`. Derive the path from the running script.

Refs wazuh/wazuh-dashboard#1605

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Fix --clear removing a CA it did not mint, and RPM ownership of a pre-staged certificate pair (#1621)

* fix(packages): only clear a shared CA the dashboard minted

--clear removed the shared root CA whenever root-ca.key existed, which also
destroys an operator-staged signing CA. Record the mint with
.wazuh-dashboard-bootstrap-ca under the credentials lock, as the manager does
with .wazuh-manager-bootstrap-ca, and delete the CA only when that marker is
present. Also remove staging directories an interrupted issue left behind,
and refuse a non-root --clear instead of reporting a clear that did not happen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): give a pre-staged certificate pair to the service user on RPM

A pair staged into /etc/wazuh-dashboard/certs before the package is
installed (e.g. by the installation assistant) is root:root, because the
service user does not exist yet. The resolver keeps an existing pair as it
finds it, so on RPM the service failed with EACCES reading
dashboard-key.pem. DEB was unaffected: its postinst already runs chown -R
on the configuration directory before the resolver.

Chown certs/ to wazuh-dashboard in %post before the resolver, on install
and upgrade, as the indexer and the manager do in their packaging. D13 now
checks the ownership and starts the service with the staged pair.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* Stop the service user from running code as root through the packages (#1620)

* build(packages): install /usr/share/wazuh-dashboard as root:root

The deb and rpm packages installed the whole installation directory as
wazuh-dashboard:wazuh-dashboard, so the service user could replace the code
that root runs from ExecStartPre=+ (bin/resolve-credentials, lib/, node/).
The directory is now root:root, with directories and executables at 755 and
other files at 644. data/ stays wazuh-dashboard:wazuh-dashboard 750 because
the dashboard writes to it at runtime. /etc/wazuh-dashboard is unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): keep root from trusting the service user's environment

/etc/default/wazuh-dashboard was owned by the service user, but root reads
it at every start: systemd passes it to ExecStartPre=+ through
EnvironmentFile=, and the SysV script sources it. The service user could
therefore choose what resolve-credentials ran as root.

- Install /etc/default/wazuh-dashboard as root:wazuh-dashboard 0640, and
  fix its ownership on upgrade in postinst and %post.
- When run as root, resolve-credentials sets a fixed PATH and unsets
  LD_PRELOAD, LD_LIBRARY_PATH and NODE_OPTIONS.
- Read wazuh-credentials.sh only from lib/ of the installation directory:
  drop the WAZUH_SHARED_HELPER_DIR override and the copy next to the script.
  The error now names the expected path.
- Run the node call in keystore_stores_verbatim as the service user.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Make the dashboard keystore readable only by its owner (#1622)

The keystore is encrypted with an empty password, so its file mode is the
only thing keeping the secrets private. It was written with the default
mode (0644 under a 022 umask), readable by every local user once the
parent directory protection is relaxed or bypassed.

Keystore.save() now creates the file with mode 0600 and restricts an
existing file before writing to it. Every writer goes through it: the
keystore CLI, and so the credentials resolver at install and pre-start.
The deb postinst and rpm %post also enforce 0600 and wazuh-dashboard
ownership on every install, so keystores created by earlier packages are
fixed on upgrade. The package install tests check the mode.

Closes #1619

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Fix the 5.x dev Docker image workflow and make plugin branches resolvable (#1593)

* Fix the 5.x dev Docker image workflow and make plugin branches resolvable

Start the Docker daemon on the AWS CodeBuild runners instead of pruning a
daemon that is not running, which aborted every scheduled run. Reduce the
schedule to a weekly build, add a plugins_branch input that falls back per
repository to the branch the workflow runs on when the branch does not exist
there, check out the requested branch in the build job, and let the inputs
default to the versions in package.json and .nvmrc.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Authenticate against Docker Hub before building the dev image

The build failed pulling node:22.22.0 with a 429 Too Many Requests: the AWS
CodeBuild runners share an IP pool that exhausts the Docker Hub anonymous pull
limit. Log in with the credentials the other build workflows already use.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Add diagnostics to the dev image build job

The build job died after 69 minutes with the build step still in progress and
no archived logs, so the failure cannot be read. Cap the job below the runner
reclaim window so GitHub stops it and keeps the logs, print the build with
plain progress, report memory, disk and kernel OOM kills after the step, and
stop the matrix from cancelling the sibling architecture.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Fall back to main when the workflow branch is missing in a plugin repository

The existence check only ran when plugins_branch was provided, so a run from a
branch of this repository that the plugin repositories do not have cloned a
non-existent branch. Walk the candidates in order - requested branch, workflow
branch, main - and use the first one that exists in each repository.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Raise the dev image build timeout to 90 minutes

With logs archived the build proved to need ~55 minutes of layers - 36 of them
in the optimizer warmup - plus the push to Quay.io, and it reports no OOM kills
and 100G of free disk. Give the job room to finish instead of cutting it in the
middle of the push.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Stop forcing the vfs storage driver on the Docker daemon

On the arm64 runner the daemon we start is the one that serves the build, and
vfs copies the whole filesystem on every layer: WORKDIR took 97s and a 1 KB
COPY took 19 minutes, against 0.2s and 0.1s on amd64, where a pre-existing
daemon on overlay2 answered instead. Reuse the running daemon when there is
one, let dockerd pick its driver otherwise, and keep vfs only as a fallback.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Pick the Docker storage driver by probing overlay stacking

Letting dockerd choose broke the arm64 job: it picked overlayfs and then failed
to mount, because / is an overlay mount on that runner and overlay does not
stack. Probe an overlay mount first, use the default driver when it works, try
fuse-overlayfs when it does not, and keep vfs as the last resort.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Build the dev image in a single expensive layer

Runners whose root filesystem is an overlay mount cannot stack overlay and fall
back to the vfs storage driver, which copies the whole tree on every layer.
Once /home/node/kbn holds node_modules that is about 19 minutes per layer, and
the checkout was followed by six of them - two WORKDIR, three COPY and two RUN
- which is over an hour of pure copying on the arm64 runner and free on amd64.
Copy the scripts before the checkout, where the tree is still empty, and run
the bootstrap, the plugin install and the optimizer warmup in one layer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Keep the image build output as an artifact

GitHub does not archive the log of a job it cancels, and the arm64 job is
cancelled by the timeout on every run, so three runs in a row left no trace of
which storage driver was chosen or how long each layer took. Tee the build
output to a file and upload it even when the step fails.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Drop the second stage of the dev image build

The stage existed to keep the intermediate layers out of the pushed image, but
the build is a single layer now and there is nothing left to drop. All it did
was copy /home/node/kbn in full - 320s on amd64, another whole-tree copy under
vfs - and chown every file in node_modules, which the git clone had already
created as node.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Raise the build timeout to 115 minutes

The CodeBuild runners now allow 120 minutes, but the job kept being cut at 90
by the workflow's own timeout, which was the lower of the two. Leave a margin
below the runner limit so GitHub is the one that stops a build that does not
finish, and the build log is uploaded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Set the build timeout to 120 minutes

Match the limit the CodeBuild runners now allow.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

---------

Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Diego García <82405377+Ripdiegozz@users.noreply.github.com>

* Keep the service user out of root's credential resolver paths (#1623)

The resolver runs as root from the maintainer scripts and ExecStartPre=+,
while /etc/wazuh-dashboard belongs to the service user. Three paths still
let that user steer root:

- --clear deleted dashboard.pem, dashboard-key.pem and root-ca.pem through
  the absolute ${CERTS_DIR} path, so a certs/ replaced with a symlink made
  root delete those names wherever it pointed, e.g. the shared CA anchor.
  It now enters certs/ as the issuing path does, removes relative to it,
  and refuses (and fails) when certs/ is not a real directory.

- The SAN list was written and read back through $(pwd -P)/<stage>/sans,
  which is resolved again through certs/ on each use. Swapping certs/
  between the two let the service user choose the names the shared CA
  signs. It is now built inside _dc_issue_pair, relative to the verified
  root-only staging directory.

- runuser kept the keystore and Node children in root's session and
  environment: from an interactive dpkg/rpm they could open root's
  terminal (TIOCSTI) and read what root exported, credentials included.
  Every child now goes through as_service_user: setsid (-w where
  util-linux has it) and env -i with only PATH and OSD_PATH_CONF.

The VM test matrix gains D22 (--clear with a symlinked certs/) and D23
(a node.options probe run from a terminal sees no tty and no root env).

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Restrict the not-ready healthcheck API to critical tasks and hide task data (#1624)

* Restrict the not-ready healthcheck API to critical tasks and hide task data

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Hide non-critical task errors on the not-ready server and escape the page output

- Replace the error of tasks that are not enabled and critical with a generic message, because it can carry node names and certificate details.
- Sort and dedupe the requested task names so reordered or repeated names share one run.
- Escape task names and errors on the not-ready page.
- Make the route test mocks return real task results so the checks exercise stored data.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Hand the kept configuration over to root on RPM removal (#1625)

Removing the RPM package deletes the wazuh-dashboard user and group but
keeps /etc/wazuh-dashboard, whose certificates, private keys and keystore
stayed owned by the freed UID and GID. The next system account created
could inherit them and read those secrets.

Before the account goes, %postun now makes root the owner of everything
the account or its group owns in /etc/wazuh-dashboard, strips group and
other access, and reports what it kept, as the Wazuh indexer package
does. A kept /etc/default/wazuh-dashboard.rpmsave loses the group too.
A fresh install takes the directory back. The package test checks both.

Related: wazuh/wazuh-dashboard-plugins#9257

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Merge 4.14.10 into 5.0.0 (#1635)

Merge 4.14.9 into 4.14.10 (#1634)

* Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------




* Merge 4.14.8 into 4.14.9 (#1614)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

* Bump 4.14.8 branch (#1612)

feat: bump 4.14.8

---------




* Bump 4.14.9 branch (#1627)

feat: bump 4.14.9

* Change tag reference for 4.14.9 (#1629)

chore(tag-reference): change tag reference for 4.14.9

---------

Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>

* Fix Indexer management and Dashboards Management menu paths in docs (#1636)

* docs: fix Indexer management menu name on the read-only mode page

The read-only mode page named a Management menu that does not exist
in 5.0; the top-level category for indexer administration is Indexer
management (src/core/utils/default_app_categories.ts:76-82).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs: replace nonexistent Stack Management entry in Discover guide

getting_started_with_discover.md pointed to a 'Stack Management'
sidebar entry that doesn't exist in the Wazuh dashboard. The app is
titled Dashboards Management, under the Dashboard management category
(src/plugins/management/public/plugin.ts:84-86), with Data sources
(src/plugins/data_source_management/common/index.ts) as one of its
sections. Fix the same wrong label in the dsm_flow.puml diagram.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs: address review feedback on dashboard menu paths

- Rewrite the Discover data selector sub-steps as a real nested list;
  the plain a.-d. lines rendered as a lazy continuation of the S3 bullet.
- Drop the nonexistent "☰" label from the Dashboards Management path and
  note that the Wazuh dashboard hard-disables home:useNewHomePage, so the
  classic navigation always applies.
- Align the workspace "Data sources" tab casing.
- Replace the leftover "stack management" mention in user_stories.md.
- Rename the stale Page-Stack alias in dsm_flow.puml and regenerate
  dsm_flow.png from it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Fix the not-ready page false success notice (#1640)

* Show the not-ready success notice only after checks

The not ready page reported that no critical errors remain while the
health checks had not run yet, because only enabled, finished and failed
tasks counted. Show the success notice only once enabled tasks finished,
and a generic waiting notice otherwise.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Log the cause of bodyless indexer response errors

Responses without an OpenSearch error object, such as the security
plugin answering 503 or 401 with plain text, were logged as
"Response Error". Include the status code, the request method and path
and the bounded plain-text body so the cause shows in the server log.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Reword the not-ready waiting notice

The page cannot tell why the health checks have no results yet: the server may be waiting for the indexer, running saved object migrations or running the checks. State only that, and point to the logs.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Mark the Wazuh changes in the OpenSearch client

configure_client.ts and its test come from OpenSearch Dashboards. Keep the original code commented out and tag each Wazuh addition.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Fix the type of the bounded log line test

The collected log entry is typed string | Error, so reading .length broke the TypeScript project build (tsc -b tsconfig.refs.json) in the bootstrap step.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

---------

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* End the package install with how to log in (#1639)

feat(packages): end the install with how to log in

Print the dashboard URL, the admin login and the start command at the end of a fresh install. Show the certificate detail only with WAZUH_DASHBOARD_VERBOSE=1.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>
Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Rodrigo López <37187963+rodrigofez@users.noreply.github.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Diego García <82405377+Ripdiegozz@users.noreply.github.com>
* Report skipped bumps in the repository bumper workflow (#1492)

Improve repository bumper error handling

* Recalculate flyout position when the sidecar is opened (#1503)

* Adapt flyout position in relation to the sidecar

* Add changelog

* Change resizable button emphasis style from :focus to :active (#1508)

* fix(sidecar): change resizable button emphasis style from :focus to :active

Update the .sidecar-resizableButton CSS to emphasize the "grab" icon
on :active instead of :focus, matching the intended interaction
feedback when dragging the resizer.

Closes https://github.com/wazuh/wazuh-dashboard-plugins/issues/8989

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): remove leftover native focus outline on resizable button

The resizable button programmatically calls .focus() on every click,
so after removing the custom :focus emphasis in favor of :active, the
browser's default focus outline was left showing as an unstyled
colored border until focus moved elsewhere. Suppress it for
mouse/touch interaction while keeping it for keyboard users via
:focus-visible.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): opt out resizable button from the global focus-ring animation

The resizable button programmatically calls .focus() on every click,
which triggered OSD's global brute-force focus-ring animation
(:focus:not([class^="eui"]):not(.osd-resetFocusState) in _base.scss)
since the button isn't an EUI component. That showed as a lingering
colored border after dragging, independent from the button's own
:active styling. Opt out via the "osd-resetFocusState" class, which is
the mechanism _base.scss already documents for components with
hand-crafted focus states, instead of fighting the rule's
!important/specificity locally. Supersedes the previous outline:none
attempt, which didn't target the actual animation.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(sidecar): allow configuring the resizable button className

Add an optional className prop to ResizableButton, and forward it from
a new classNameButton option on OverlaySidecarOpenOptions/Sidecar, so
callers of overlays.sidecar.open() can style/opt-out the resizer
button (e.g. pass "osd-resetFocusState" to drop the global focus-ring
animation) without hardcoding it in the component.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Change top bar health-check icon (#1505)

* feat: update health check indicator

* Change top bar health-check icon to a pulse shown only when attention is needed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(core): use kebab-case for sidecar docked-mode CSS variable

Rename --osdSidecarSize to --osd-sidecar-size and switch attribute
selectors to double quotes to satisfy the repo's stylelint rules
(custom-property-pattern, string-quotes), registering sidecar.scss
in the global selectors allowlist for its .euiFlyout references.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* chore: use constant

* Rework health-check popover

* Rework health-check popover

* List failing health checks in the nav-button popover

Show the enabled non-green checks as an EuiHealth list in the health-check
popover, labelled by the check name and with the error surfaced in a tooltip.
Use the shared mapTaskStatusToHealthColor helper and TASK.RUN_RESULT constants
instead of magic strings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Fix popover closes when clicking inside

* Close popover after navigating to the health check

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Bump 5.0.0 branch (#1513)

feat: bump 5.0.0

* Fix RPM changelog entry order causing build failure (#1516)

Fix RPM changelog entry order for 5.0.0

The 5.0.0 changelog entry was placed out of descending chronological
order, causing rpmbuild to fail while parsing %changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1517)

Remove unnecessary debhelper install-time dependency (#1484)

fix: remove unnecessary debhelper install-time dependency

debhelper is only required to build the .deb package (declared under
Build-Depends in dev-tools/build-packages/deb/debian/control), not to
install a pre-built one. Remove it from the apt-get install steps used
to test package install/upgrade.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1537)

Merge 4.14.9 into 5.0.0: no changes (verified 2026-08-28)

* fix: remove inert opensearch_security.cookie.ttl setting (#1534)

The dashboard config declares opensearch_security.cookie.ttl, but the
security plugin never reads it: only opensearch_security.session.ttl
governs session/cookie expiry. Shipping the setting misleads operators
into believing it bounds the cookie lifetime.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Bump 5.0.0 branch (#1545)

feat: bump 5.0.0

* Revert bump 5.0.0 branch (#1546)

feat: revert 5.0.0 references

* Fix changelog not in descending chronological order (#1548)

* fix: keep RPM changelog entries in descending date order on re-bump (#1549)

Re-bumping an existing version updated its date in place instead of
repositioning it, so a newer date could end up below older entries and
rpmbuild rejected the spec (%changelog not in descending chronological
order). The entry is now removed and reinserted at the position
matching its date.

Also fixes date/sed portability on macOS (BSD date/sed vs GNU), and
makes an invalid date abort the script instead of writing the error
text into the changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Bump 5.0.0 branch (#1551)

feat: bump 5.0.0

* Review the 5.0.0 changelog (#1556)

* docs(changelog): review the 5.0.0 entries

Removed the open redirect fix entry (#1285) and the pre install script
check entry (#1328, #1365).

Reordered the sections to Added, Changed, Removed, Fixed, and qualified
the two wazuh-dashboard-plugins references so they no longer read as
wazuh-dashboard issues.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): reference issues instead of pull requests

Each entry now links the issue the pull request closed, so the reference
carries the description and the discussion instead of just the diff.

Where an entry listed several references that resolve the same issue, it
collapses to that one; where they resolve different issues, the entry
keeps the main one and the rest are attached to it as sub-issues on
GitHub, following the shape of wazuh-dashboard-plugins#8789.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): merge the health check service and app entries

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* docs(changelog): point the health check entry at its parent issue

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1563)

Merge 4.14.8 into 4.14.9 (#1562)

Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x
# Conflicts:
#	dev-tools/build-dev-image/README.md
#	dev-tools/build-dev-image/build-multiarch.sh
#	dev-tools/build-dev-image/install-plugins.sh
#	dev-tools/build-dev-image/plugins
#	dev-tools/build-dev-image/warmup-opensearch_dashboards.yml
#	dev-tools/build-dev-image/warmup-optimizer.sh
#	dev-tools/build-dev-image/wzd.dockerfile

* Bump 5.0.0 branch (#1567)

feat: bump 5.0.0

* Bump 5.0.0 branch (#1571)

feat: bump 5.0.0

* Fix empty error message in dashboard save failure toast (#1573)

The danger toast shown when saving a dashboard fails interpolated
savedDashboard.message, a property that does not exist on the saved
object instance, so the message always rendered as
"Dashboard 'X' was not saved. Error:" with nothing after "Error:".

Use the caught error's message instead.

Closes #1568

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Show the root cause of the failure in the error toast full error modal (#1574)

The See the full error modal built its copyable block from caused_by, which
can hold a failure raised while the response itself was being built rather
than the failure that made the request fail: querying a field that is not
searchable reported a null_pointer_exception about reducePhase.aggregations
instead of the query_shard_exception the backend reports under root_cause.

The reason of the root cause is now shown inside the danger callout, under
the message of the error, and is stripped of URLs, IP addresses and
filesystem paths. The copyable block keeps the content it had on 5.0.0,
the client stack trace included.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Merge 4.14.9 into 5.0.0 (#1581)

Merge 4.14.8 into 4.14.9 (#1580)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Reorder rpm changelog

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>

* Merge 4.14.10 into 5.0.0 (#1602)

* Bump 4.14.10 branch (#1589)

feat: bump 4.14.10

* Merge 4.14.9 into 4.14.10 (#1601)

Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Let a health check task report red, and show that red in the overall status (#1595)

* feat: Add TaskResult so health check tasks report their own result status

A health check task could only resolve or throw, and the registration-time
`critical` flag decided whether a throw became yellow or red. Because that same
flag also decides whether a failure blocks startup, a task had no way to report
red without holding the dashboard behind the "server is not ready yet" screen.

A task may now resolve a branded `TaskResult` and pick its own result status.
`critical` is untouched and goes on deciding whether a red result blocks
startup, so the new reachable combination is a non-critical red: visible,
without blocking.

The result is branded with a registry symbol rather than detected structurally.
An existing task already resolves `{ status: 'ok' }` as its data, so a
structural guard would reinterpret plain task data as a status and drop the
payload.

Tasks that resolve or throw are unaffected. No existing task changes.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* fix: Respect the check own result when computing the health check overall status

computeOverallStatus decided the overall status only from the critical flag,
so a check reporting red landed on the header as yellow. Every check registered
by the Wazuh plugins is non critical, which capped the indicator at yellow and
made red unreachable.

The aggregation now returns red for any finished check whose result is red,
keeps escalating a non green critical check to red, and returns yellow for any
other non green result.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* fix: Type the health check task error property as string or null

`public error = null` made TypeScript infer the literal type `null`, so
assigning a TaskResult message broke `tsc -b tsconfig.refs.json` and the CI
bootstrap. The catch branch got away with the same assignment because a catch
binding is `any`.

`ITask['error']` is already `string | null`, which is what the property held
all along.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* docs: Drop the redundant health check changelog entry

The overall status aggregation was not fixing a defect users could reach. In
5.0.0 the only assignment of a red result sits behind `if (this.critical)`, so
a non-critical red does not exist and the old aggregation was equivalent to the
new one. That state is created by this branch, so the behaviour belongs to the
Added entry rather than to a separate Fixed one.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* change: Require health check tasks to return a task result

A task could resolve any value, which the platform stored as data and marked
green, or resolve a branded TaskResult. Two return shapes for one outcome, and
the plain one gave a task no way to say anything but green.

`TaskDefinition.run` now returns a TaskResult. A value that is not branded is
rejected at runtime as well, because the type does not reach a task written in
JavaScript, and a silent gray result would be worse than a loud failure.

Throwing is unchanged and stays the path for the unexpected.

BREAKING CHANGE: every registered task must return taskResult.ok, warning or
error. The tasks in wazuh-dashboard-plugins migrate alongside this.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* docs: Update the health check README for the task result contract

The README documented the semantics this branch inverts. It stated in six
places that the result color encodes criticality: red meant a critical failure
and yellow a non-critical one, and the summary went red only for a critical
task. That held while the only path to red was a throw from a critical task.

It also described the summary with the startup blocking rule. Those are two
aggregations answering different questions, and only one of them changed, so
they are now documented apart.

The registration example returned nothing, which the new contract rejects.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Break word to prevent overflow

* change: Provide the result constructors in the health check task context

A task had to build its TaskResult itself, and core exported no constructor to
build one with. wazuh-dashboard-plugins answered that by hand-rolling a mirror
of the contract, relying on Symbol.for to resolve to the same brand. A required
contract nobody can import is a contract everybody copies.

The context a task already receives now carries the constructors, so a task
reports a result without importing anything. TaskRunContext replaces the `any`
the run parameter used to be, and the contract types are exported by name,
closing the TODO that kept them private.

Suggested by @Desvelao in review.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* refactor: Remove the unused health check ITask from the common types

It declared `run` as returning a generic `Promise<Result>`, which contradicts
both the task contract and the `ITask` the server defines. Nothing imported it,
in this repo or in wazuh-dashboard-plugins.

The name still exists in the server task types, which is the one implemented.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* change: Export the health check task contract from the server entry point

A plugin registering a check could not import TaskDefinition, TaskRunContext,
TaskResult or TaskResultFactory from src/core/server, so it redeclared them.
They are exported there now.

The manager annotates the context it passes, so the compiler checks that the
injected constructors reach the task.

The README interface block now matches the type: run receives a TaskRunContext,
critical is optional, and there is no index signature for extra fields.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

---------

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* feat(core): configurable version, help menu links, and an About page (#1609)

* feat(core): add configurable version, help menu links, and an About page

- opensearchDashboards.branding.applicationVersion overrides the version
  shown in the About page and the persistent help-menu badge; falls back
  to the real build version.
- opensearchDashboards.branding.helpMenuLinks overrides the help menu's
  Documentation/Slack/GitHub/Google Group list (replaces it entirely when
  set); each entry supports an optional darkModeIcon.
- New src/plugins/about core plugin hosts the About page (moved out of
  wazuh-dashboard-plugins), with its own about.communityLinks setting
  (same {label, link, icon, darkModeIcon} shape, hides the Community
  panel when set to an empty list), registered under the same "Dashboard
  management" category/position the page had before the move.
- Synced the legacy Joi config schema (src/legacy/server/config/schema.js)
  with the new branding.* keys to fix a boot-time validation error.
- Registered the new "about" i18n namespace in src/.i18nrc.json.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): use the Wazuh copyright header on new about plugin files

The new files added for the about plugin and help_menu type used the
"Copyright OpenSearch Contributors" header template, reserved for
OpenSearch-authored files. These are wholly new, Wazuh-original files, so
per this fork's own convention (.eslintrc.js OSD_WAZUH header, "For new
files created by Wazuh Contributors") they should use "Copyright Wazuh"
instead.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs(changelog): add entries for the about plugin and branding settings

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): hide all help menu links when helpMenuLinks is empty

Treat opensearchDashboards.branding.helpMenuLinks as configured whenever it
is set, so an empty list renders no links instead of falling back to the
built-in ones, matching about.communityLinks and the documented behavior.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): register the About app in the all nav group

Add the About app to DEFAULT_NAV_GROUPS.all under the Dashboard
management category so it stays visible once the new navigation is
enabled. Previously it reached the nav group through the main plugin's
registerWazuhNavLinks, which no longer lists it after the move.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* fix(core): set the About page breadcrumb and document title

The About app never set its breadcrumb or document title, so the header
kept showing the previous app's breadcrumb (e.g. "Overview") and the tab
title stayed "Wazuh". Set both to "About" when the app mounts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Merge 4.14.10 into 5.0.0 (#1616)

Merge 4.14.9 into 4.14.10 (#1615)

* Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------




* Merge 4.14.8 into 4.14.9 (#1614)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

* Bump 4.14.8 branch (#1612)

feat: bump 4.14.8

---------




---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Resolve dashboard credentials at install and start (#1613)

* feat(packages): resolve dashboard credentials at install and start

Replace the hardcoded kibanaserver keystore pair and the plaintext
wazuh-wui password with the shared resolve-credentials script, run from
postinst/%post and from the unit's ExecStartPre=+. The script is
downloaded and checksum-verified at build time. Purge removes /etc/wazuh
only when no other Wazuh central component remains.

Closes #1594

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): ship the credentials resolver in the repo

Replace the build-time download of resolve-credentials with a script
maintained in this repository, adapted from the manager's resolver.
Only the shared wazuh-credentials.sh library is still downloaded at
build time, from wazuh-installation-assistant, into lib/.

The resolver takes --install, --upgrade, --prestart and --clear. The
maintainer scripts, the systemd unit and the SysV init script call it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): honour credentials set in the dashboard config

Treat opensearch.password and wazuh_core.hosts.default.password set in
opensearch_dashboards.yml as resolved, so the resolver neither refuses
the start nor writes keystore entries that would override the yml.
Never write opensearch.username over a user set in the yml, and skip
the wazuh-wui entry when the yml defines no default host.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): generate the AI assistant key in the resolver

Move the wazuh_ai_assistant.encryptionKey generation out of postinst
and %post into resolve-credentials. It is generated on --install and
--prestart when neither the keystore nor opensearch_dashboards.yml has
it, never on --upgrade, and never replaced. A generation failure only
warns. --clear now removes it too, so an image does not share one key
across containers.

The resolver already creates the keystore, so the maintainer scripts no
longer do.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): pick the credentials library ref from the build

Try an ordered list of wazuh-installation-assistant refs (override, tag
being built, branch being built, version branch, version tag) instead of
a single ref. A tag build only tries its tag.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): supply credentials before starting the service in CI

The unit now runs resolve-credentials --prestart, which refuses to start
while the kibanaserver and wazuh-wui passwords are unresolved. The DEB
install test started the service on a clean install with no credentials,
so the start failed.

Assert the refusal first, then write test credentials to
/etc/wazuh/credentials.env and start the service. Dump the unit journal
on failure.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): issue the dashboard TLS certificates from the shared CA

On a fresh install, resolve-credentials now issues dashboard.pem and
dashboard-key.pem, and installs root-ca.pem, into
/etc/wazuh-dashboard/certs from the shared Wazuh root CA (/etc/wazuh/ca).
The CA is created through the shared credentials library when no
component has created it yet, and reused otherwise.

An existing complete pair is kept, a partial pair is refused, and an
anchor-only CA cannot issue, so the operator is told to stage a pair.
--upgrade and --prestart never touch the certificates; --clear removes
them together with a CA minted on this host. Files are staged in a
root-only directory and published with ln -T, and each step is logged
with public data only.

The packages now depend on openssl (and diffutils and util-linux on
RPM), which the issuance and the shared library need.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs(packages): reference the manager's certificate issuance

Point the dashboard certificate step and its README to the manager's
issue and PR it mirrors: wazuh/wazuh#39554 and wazuh/wazuh#39571.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* revert: reference the manager's certificate issuance

This reverts commit e9bde535c6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): supply credentials before starting the service in RPM CI

The unit runs resolve-credentials --prestart, which refuses to start while
the kibanaserver and wazuh-wui passwords are unresolved. The RPM install
test still started the service on a clean install with no credentials, so
the start failed (run 36148424354).

Move the inline SSH test into rpm-test-install-uninstall.sh, mirroring the
DEB test: check the issued certificates, assert the refusal, write test
credentials to /etc/wazuh/credentials.env, start the service and dump the
unit journal on failure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): only reject passwords the keystore would not store verbatim

resolve-credentials validated the consumed kibanaserver and wazuh-wui
passwords against the shared password policy. That policy is fetched
unpinned from wazuh-installation-assistant and has since gained a symbol
requirement, so the CI test passwords were rejected and the service did
not start (run 36389268794). The dashboard's own message already
described an older version of the rule.

The indexer and the manager own these passwords and enforce the policy.
The dashboard now checks only what is its own concern: keystore add
trims the value and stores it JSON.parse'd, so reject any value it would
not store verbatim (JSON numbers, booleans, quoted strings, arrays,
objects, surrounding whitespace). The check repeats add.js with the
bundled Node.

Add a negative case to the DEB and RPM install tests asserting that a
JSON number is reported as INVALID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): add a VM test matrix for install and start

vm-test-matrix.sh runs 21 cases against a built .deb or .rpm on a
disposable VM: fresh install, credentials from credentials.env, the
environment and the yml, invalid values, a refused credentials file,
shared CA reuse, anchor-only CA, operator and partial certificate pairs,
custom SANs, --clear, removal, reinstall and, with --previous, upgrades.
The host is wiped after every case and a summary is printed.
--clean-only wipes the host without running a case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): cover install orders with the manager and indexer

Rename --package and --previous to --dashboard and --dashboard-previous,
and add --manager and --indexer. Dashboard-only cases are now D01-D21;
the new F01-F08 cases need both sibling packages and run only when they
are given.

F01-F06 install the indexer, the manager and the dashboard in every
order and check after each step that the dashboard resolves exactly
what credentials.env holds, names what it lacks, refuses to start until
both keys are resolved, and reuses or mints the shared CA. F07 purges
the dashboard with the siblings still installed; F08 reinstalls it. The
siblings' own start and CA are recorded as [INFO].

Cleanup purges wazuh-manager and wazuh-indexer too when their packages
are given, or with --force.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): let the service group read the shared credentials library

At startup OSD's i18n loader globs */.i18nrc.json under the installation
root, which lists every top-level directory. lib/ was root:root 0750, so
the wazuh-dashboard user got EACCES on scandir and the server exited with
a fatal error.

Keep lib/ and wazuh-credentials.sh owned by root, so the service user
still cannot modify what ExecStartPre=+ sources as root, but give them
the wazuh-dashboard group (0750 / 0640) so the loader can list the
directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): read the keystore before grepping it in CI

`keystore list | grep -q` under `pipefail` failed when grep closed the
pipe on the first match and the keystore CLI hit EPIPE, reporting the AI
assistant key as missing although it was present (RPM aarch64).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Check Prettier only on the lines a change writes (#1608)

* fix(ci): check Prettier only on the lines a change writes

The check runs over every file a change touches. Most of this repository
comes from OpenSearch Dashboards, which never ran Prettier over its own
tree, so changing two lines in a file that was never formatted demands a
reformat of the whole file. On wazuh/wazuh-dashboard-alerting#148 that was
318 lines of rewriting to land 400 lines of work.

No configuration fixes this. Sweeping nine Prettier versions from 1.19.1 to
3.6.2 and every single-option change against upstream's own `.prettierrc`
leaves a floor of 73 of 670 source files failing. There is nothing to align
to.

Rewriting those files is what costs us. Each one diverges from its
counterpart on the other version branches, so the next upward merge or
cherry-pick conflicts, and the next OpenSearch migration replays a larger
Wazuh delta onto the new upstream tree.

So a change answers for the lines it writes and nothing else. A file it adds
is checked in full; a line it did not touch is not checked.

`scripts/prettier-check-changed.js` compares what the change wrote against
what Prettier wants and reports the overlap. `--fix` corrects those lines
and leaves the rest of the file alone. A merge branch passes the branch
being merged as a second base, so lines that exist in either parent are not
the merge's own. The pre-commit hook returns early during a merge,
cherry-pick, revert or rebase, where it was blocking
`git cherry-pick --continue` during the scheduled merges.

Backtested over 43 merged pull requests across the six repositories it
spares 28 of 29 files, with no false positives.

Refs wazuh/wazuh-dashboard#1605

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(ci): compare against the merge base and follow renames

Three problems found in review.

The check diffed against the tip of the base branch. When the base moves
ahead after a pull request branches off, that diff also reports the base's
own later commits, in reverse, and blames them on the change. A pull request
that adds one line was asked to reformat a line the base had already fixed.
Resolve each base with `git merge-base <ref> HEAD` instead, which is what
GitHub uses for "Files changed", so the check and the diff a reviewer reads
agree. The workflow needs the shared history for that, so the checkout takes
`fetch-depth: 0`.

A renamed file was checked in full. Git cannot pair a rename when the diff
receives only the new path, so it reported the file as added. Pass both paths.
The rename map was also built against the first base alone, so with two bases
the second lookup missed and the file looked new again; build one map per
base. Any upward merge carrying a rename hit this.

The `--fix` hint named `scripts/`, which is wrong in `wazuh-dashboard` where
the script lives in `dev-tools/`. Derive the path from the running script.

Refs wazuh/wazuh-dashboard#1605

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Fix --clear removing a CA it did not mint, and RPM ownership of a pre-staged certificate pair (#1621)

* fix(packages): only clear a shared CA the dashboard minted

--clear removed the shared root CA whenever root-ca.key existed, which also
destroys an operator-staged signing CA. Record the mint with
.wazuh-dashboard-bootstrap-ca under the credentials lock, as the manager does
with .wazuh-manager-bootstrap-ca, and delete the CA only when that marker is
present. Also remove staging directories an interrupted issue left behind,
and refuse a non-root --clear instead of reporting a clear that did not happen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): give a pre-staged certificate pair to the service user on RPM

A pair staged into /etc/wazuh-dashboard/certs before the package is
installed (e.g. by the installation assistant) is root:root, because the
service user does not exist yet. The resolver keeps an existing pair as it
finds it, so on RPM the service failed with EACCES reading
dashboard-key.pem. DEB was unaffected: its postinst already runs chown -R
on the configuration directory before the resolver.

Chown certs/ to wazuh-dashboard in %post before the resolver, on install
and upgrade, as the indexer and the manager do in their packaging. D13 now
checks the ownership and starts the service with the staged pair.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* Stop the service user from running code as root through the packages (#1620)

* build(packages): install /usr/share/wazuh-dashboard as root:root

The deb and rpm packages installed the whole installation directory as
wazuh-dashboard:wazuh-dashboard, so the service user could replace the code
that root runs from ExecStartPre=+ (bin/resolve-credentials, lib/, node/).
The directory is now root:root, with directories and executables at 755 and
other files at 644. data/ stays wazuh-dashboard:wazuh-dashboard 750 because
the dashboard writes to it at runtime. /etc/wazuh-dashboard is unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): keep root from trusting the service user's environment

/etc/default/wazuh-dashboard was owned by the service user, but root reads
it at every start: systemd passes it to ExecStartPre=+ through
EnvironmentFile=, and the SysV script sources it. The service user could
therefore choose what resolve-credentials ran as root.

- Install /etc/default/wazuh-dashboard as root:wazuh-dashboard 0640, and
  fix its ownership on upgrade in postinst and %post.
- When run as root, resolve-credentials sets a fixed PATH and unsets
  LD_PRELOAD, LD_LIBRARY_PATH and NODE_OPTIONS.
- Read wazuh-credentials.sh only from lib/ of the installation directory:
  drop the WAZUH_SHARED_HELPER_DIR override and the copy next to the script.
  The error now names the expected path.
- Run the node call in keystore_stores_verbatim as the service user.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Make the dashboard keystore readable only by its owner (#1622)

The keystore is encrypted with an empty password, so its file mode is the
only thing keeping the secrets private. It was written with the default
mode (0644 under a 022 umask), readable by every local user once the
parent directory protection is relaxed or bypassed.

Keystore.save() now creates the file with mode 0600 and restricts an
existing file before writing to it. Every writer goes through it: the
keystore CLI, and so the credentials resolver at install and pre-start.
The deb postinst and rpm %post also enforce 0600 and wazuh-dashboard
ownership on every install, so keystores created by earlier packages are
fixed on upgrade. The package install tests check the mode.

Closes #1619

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Fix the 5.x dev Docker image workflow and make plugin branches resolvable (#1593)

* Fix the 5.x dev Docker image workflow and make plugin branches resolvable

Start the Docker daemon on the AWS CodeBuild runners instead of pruning a
daemon that is not running, which aborted every scheduled run. Reduce the
schedule to a weekly build, add a plugins_branch input that falls back per
repository to the branch the workflow runs on when the branch does not exist
there, check out the requested branch in the build job, and let the inputs
default to the versions in package.json and .nvmrc.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Authenticate against Docker Hub before building the dev image

The build failed pulling node:22.22.0 with a 429 Too Many Requests: the AWS
CodeBuild runners share an IP pool that exhausts the Docker Hub anonymous pull
limit. Log in with the credentials the other build workflows already use.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Add diagnostics to the dev image build job

The build job died after 69 minutes with the build step still in progress and
no archived logs, so the failure cannot be read. Cap the job below the runner
reclaim window so GitHub stops it and keeps the logs, print the build with
plain progress, report memory, disk and kernel OOM kills after the step, and
stop the matrix from cancelling the sibling architecture.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Fall back to main when the workflow branch is missing in a plugin repository

The existence check only ran when plugins_branch was provided, so a run from a
branch of this repository that the plugin repositories do not have cloned a
non-existent branch. Walk the candidates in order - requested branch, workflow
branch, main - and use the first one that exists in each repository.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Raise the dev image build timeout to 90 minutes

With logs archived the build proved to need ~55 minutes of layers - 36 of them
in the optimizer warmup - plus the push to Quay.io, and it reports no OOM kills
and 100G of free disk. Give the job room to finish instead of cutting it in the
middle of the push.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Stop forcing the vfs storage driver on the Docker daemon

On the arm64 runner the daemon we start is the one that serves the build, and
vfs copies the whole filesystem on every layer: WORKDIR took 97s and a 1 KB
COPY took 19 minutes, against 0.2s and 0.1s on amd64, where a pre-existing
daemon on overlay2 answered instead. Reuse the running daemon when there is
one, let dockerd pick its driver otherwise, and keep vfs only as a fallback.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Pick the Docker storage driver by probing overlay stacking

Letting dockerd choose broke the arm64 job: it picked overlayfs and then failed
to mount, because / is an overlay mount on that runner and overlay does not
stack. Probe an overlay mount first, use the default driver when it works, try
fuse-overlayfs when it does not, and keep vfs as the last resort.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Build the dev image in a single expensive layer

Runners whose root filesystem is an overlay mount cannot stack overlay and fall
back to the vfs storage driver, which copies the whole tree on every layer.
Once /home/node/kbn holds node_modules that is about 19 minutes per layer, and
the checkout was followed by six of them - two WORKDIR, three COPY and two RUN
- which is over an hour of pure copying on the arm64 runner and free on amd64.
Copy the scripts before the checkout, where the tree is still empty, and run
the bootstrap, the plugin install and the optimizer warmup in one layer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Keep the image build output as an artifact

GitHub does not archive the log of a job it cancels, and the arm64 job is
cancelled by the timeout on every run, so three runs in a row left no trace of
which storage driver was chosen or how long each layer took. Tee the build
output to a file and upload it even when the step fails.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Drop the second stage of the dev image build

The stage existed to keep the intermediate layers out of the pushed image, but
the build is a single layer now and there is nothing left to drop. All it did
was copy /home/node/kbn in full - 320s on amd64, another whole-tree copy under
vfs - and chown every file in node_modules, which the git clone had already
created as node.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Raise the build timeout to 115 minutes

The CodeBuild runners now allow 120 minutes, but the job kept being cut at 90
by the workflow's own timeout, which was the lower of the two. Leave a margin
below the runner limit so GitHub is the one that stops a build that does not
finish, and the build log is uploaded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Set the build timeout to 120 minutes

Match the limit the CodeBuild runners now allow.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

---------

Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Diego García <82405377+Ripdiegozz@users.noreply.github.com>

* Keep the service user out of root's credential resolver paths (#1623)

The resolver runs as root from the maintainer scripts and ExecStartPre=+,
while /etc/wazuh-dashboard belongs to the service user. Three paths still
let that user steer root:

- --clear deleted dashboard.pem, dashboard-key.pem and root-ca.pem through
  the absolute ${CERTS_DIR} path, so a certs/ replaced with a symlink made
  root delete those names wherever it pointed, e.g. the shared CA anchor.
  It now enters certs/ as the issuing path does, removes relative to it,
  and refuses (and fails) when certs/ is not a real directory.

- The SAN list was written and read back through $(pwd -P)/<stage>/sans,
  which is resolved again through certs/ on each use. Swapping certs/
  between the two let the service user choose the names the shared CA
  signs. It is now built inside _dc_issue_pair, relative to the verified
  root-only staging directory.

- runuser kept the keystore and Node children in root's session and
  environment: from an interactive dpkg/rpm they could open root's
  terminal (TIOCSTI) and read what root exported, credentials included.
  Every child now goes through as_service_user: setsid (-w where
  util-linux has it) and env -i with only PATH and OSD_PATH_CONF.

The VM test matrix gains D22 (--clear with a symlinked certs/) and D23
(a node.options probe run from a terminal sees no tty and no root env).

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Restrict the not-ready healthcheck API to critical tasks and hide task data (#1624)

* Restrict the not-ready healthcheck API to critical tasks and hide task data

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Hide non-critical task errors on the not-ready server and escape the page output

- Replace the error of tasks that are not enabled and critical with a generic message, because it can carry node names and certificate details.
- Sort and dedupe the requested task names so reordered or repeated names share one run.
- Escape task names and errors on the not-ready page.
- Make the route test mocks return real task results so the checks exercise stored data.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Hand the kept configuration over to root on RPM removal (#1625)

Removing the RPM package deletes the wazuh-dashboard user and group but
keeps /etc/wazuh-dashboard, whose certificates, private keys and keystore
stayed owned by the freed UID and GID. The next system account created
could inherit them and read those secrets.

Before the account goes, %postun now makes root the owner of everything
the account or its group owns in /etc/wazuh-dashboard, strips group and
other access, and reports what it kept, as the Wazuh indexer package
does. A kept /etc/default/wazuh-dashboard.rpmsave loses the group too.
A fresh install takes the directory back. The package test checks both.

Related: wazuh/wazuh-dashboard-plugins#9257

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Merge 4.14.10 into 5.0.0 (#1635)

Merge 4.14.9 into 4.14.10 (#1634)

* Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------




* Merge 4.14.8 into 4.14.9 (#1614)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

* Bump 4.14.8 branch (#1612)

feat: bump 4.14.8

---------




* Bump 4.14.9 branch (#1627)

feat: bump 4.14.9

* Change tag reference for 4.14.9 (#1629)

chore(tag-reference): change tag reference for 4.14.9

---------

Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>

* Fix Indexer management and Dashboards Management menu paths in docs (#1636)

* docs: fix Indexer management menu name on the read-only mode page

The read-only mode page named a Management menu that does not exist
in 5.0; the top-level category for indexer administration is Indexer
management (src/core/utils/default_app_categories.ts:76-82).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs: replace nonexistent Stack Management entry in Discover guide

getting_started_with_discover.md pointed to a 'Stack Management'
sidebar entry that doesn't exist in the Wazuh dashboard. The app is
titled Dashboards Management, under the Dashboard management category
(src/plugins/management/public/plugin.ts:84-86), with Data sources
(src/plugins/data_source_management/common/index.ts) as one of its
sections. Fix the same wrong label in the dsm_flow.puml diagram.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs: address review feedback on dashboard menu paths

- Rewrite the Discover data selector sub-steps as a real nested list;
  the plain a.-d. lines rendered as a lazy continuation of the S3 bullet.
- Drop the nonexistent "☰" label from the Dashboards Management path and
  note that the Wazuh dashboard hard-disables home:useNewHomePage, so the
  classic navigation always applies.
- Align the workspace "Data sources" tab casing.
- Replace the leftover "stack management" mention in user_stories.md.
- Rename the stale Page-Stack alias in dsm_flow.puml and regenerate
  dsm_flow.png from it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Fix the not-ready page false success notice (#1640)

* Show the not-ready success notice only after checks

The not ready page reported that no critical errors remain while the
health checks had not run yet, because only enabled, finished and failed
tasks counted. Show the success notice only once enabled tasks finished,
and a generic waiting notice otherwise.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Log the cause of bodyless indexer response errors

Responses without an OpenSearch error object, such as the security
plugin answering 503 or 401 with plain text, were logged as
"Response Error". Include the status code, the request method and path
and the bounded plain-text body so the cause shows in the server log.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Reword the not-ready waiting notice

The page cannot tell why the health checks have no results yet: the server may be waiting for the indexer, running saved object migrations or running the checks. State only that, and point to the logs.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Mark the Wazuh changes in the OpenSearch client

configure_client.ts and its test come from OpenSearch Dashboards. Keep the original code commented out and tag each Wazuh addition.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Fix the type of the bounded log line test

The collected log entry is typed string | Error, so reading .length broke the TypeScript project build (tsc -b tsconfig.refs.json) in the bootstrap step.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

---------

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* End the package install with how to log in (#1639)

feat(packages): end the install with how to log in

Print the dashboard URL, the admin login and the start command at the end of a fresh install. Show the certificate detail only with WAZUH_DASHBOARD_VERBOSE=1.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Bump 5.0.0 branch (#1645)

feat: bump 5.0.0

* Revert bump 5.0.0 branch (#1647)

feat: revert 5.0.0 references

* Bump 5.0.0 branch (#1650)

feat: bump 5.0.0

* Name the browser tab after the current app and add a skip link (#1643)

* fix(chrome): name the browser tab after the current app

Set the tab title to "<app title> - <applicationTitle>" on every app change instead of resetting it to the base title, so every plugin's app gets a distinct title. Fall back to Wazuh instead of OpenSearch Dashboards when applicationTitle is invalid.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* feat(rendering): add a skip to main content link

Render a skip link before the header, hidden until focused with Tab. Enter moves focus to the app wrapper without changing the URL hash, which the apps use for routing. Not rendered while the header is hidden, such as on the login page.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>

* Fix Timeline label regex blocking the server (#1652)

fix(timeline): run .label() regex with re2js to avoid ReDoS

A user-supplied .label() regex ran on native RegExp, so a nested quantifier could block the server's event loop. re2js runs in linear time and rejects backreferences and lookarounds.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Minify the production bundles (#1646)

* feat(optimizer): minify the production bundles

Enable SWC compress and mangle for the optimizer bundles, which were
shipped with both disabled since the fork from Kibana.

Keep class and function names: code reads constructor.name (error
messages, error boundaries), and Babel compiles our classes to
functions, so keep_classnames alone does not protect them.

On a local amd64 package built from the same commits as the CI one,
the entry bundles shrink 38% decoded and 26% brotli, and the deb 3.3%.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* test(optimizer): update the dist bundle snapshot

The production bundles are now compressed and mangled, so the dist
snapshot of the foo and bar fixture bundles holds the minified code.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

---------

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Disable and reload the wazuh-dashboard systemd unit on RPM and DEB removal (#1654)

* fix(packaging): disable wazuh-dashboard systemd unit on RPM removal

systemctl stop in the %preun scriptlet left the unit enabled, leaving a
dangling multi-user.target.wants symlink and a not-found unit once the
RPM deleted the unit file. Mirror the DEB prerm and the wazuh-indexer
RPM by also running systemctl --no-reload disable before removal.

Closes #1653

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packaging): mirror the indexer's stop/disable/reload sequence in the RPM and DEB packages

The RPM %preun already stops and disables the unit, but nothing told
systemd to forget it once the unit file was actually removed, so
systemctl list-units could keep reporting it as not-found until some
unrelated reload happened. The DEB prerm disabled the unit without
--no-reload, and its postrm never reloaded either. Add the matching
daemon-reload to %postun/postrm, and --no-reload to the DEB disable
call, exactly as the wazuh-indexer RPM and DEB packages already do.

Closes #1653

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packaging): add --no-reload to the RPM stop call, matching the indexer

The DEB prerm and the wazuh-indexer RPM both suppress the reload on
stop since disable (right after) reloads once anyway; the dashboard
RPM's stop call was missing that flag.

Closes #1653

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packaging): add --no-reload to the RPM's upgrade stop call too

%pre stops the running service before an in-place upgrade, same as
%preun does before removal. The wazuh-indexer RPM suppresses the
reload there too, since the unit file isn't changing yet.

Closes #1653

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Rename wazuh-wui to wazuh-internal-client (#1651)

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Configura CA validation by default (#1660)

* Merge 4.14.10 into 5.0.0 (#1671)

Merge 4.14.9 into 4.14.10 (#1664)

* Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------




* Merge 4.14.8 into 4.14.9 (#1614)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

* Bump 4.14.8 branch (#1612)

feat: bump 4.14.8

---------




* Bump 4.14.9 branch (#1627)

feat: bump 4.14.9

* Change tag reference for 4.14.9 (#1629)

chore(tag-reference): change tag reference for 4.14.9

* Bump 4.14.9 branch (#1656)

feat: bump 4.14.9

* Change tag reference for 4.14.9 (#1657)

chore(tag-reference): change tag reference for 4.14.9

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>
Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Rodrigo López <37187963+rodrigofez@users.noreply.github.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Diego García <82405377+Ripdiegozz@users.noreply.github.com>
* Report skipped bumps in the repository bumper workflow (#1492)

Improve repository bumper error handling

* Recalculate flyout position when the sidecar is opened (#1503)

* Adapt flyout position in relation to the sidecar

* Add changelog

* Change resizable button emphasis style from :focus to :active (#1508)

* fix(sidecar): change resizable button emphasis style from :focus to :active

Update the .sidecar-resizableButton CSS to emphasize the "grab" icon
on :active instead of :focus, matching the intended interaction
feedback when dragging the resizer.

Closes https://github.com/wazuh/wazuh-dashboard-plugins/issues/8989

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): remove leftover native focus outline on resizable button

The resizable button programmatically calls .focus() on every click,
so after removing the custom :focus emphasis in favor of :active, the
browser's default focus outline was left showing as an unstyled
colored border until focus moved elsewhere. Suppress it for
mouse/touch interaction while keeping it for keyboard users via
:focus-visible.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): opt out resizable button from the global focus-ring animation

The resizable button programmatically calls .focus() on every click,
which triggered OSD's global brute-force focus-ring animation
(:focus:not([class^="eui"]):not(.osd-resetFocusState) in _base.scss)
since the button isn't an EUI component. That showed as a lingering
colored border after dragging, independent from the button's own
:active styling. Opt out via the "osd-resetFocusState" class, which is
the mechanism _base.scss already documents for components with
hand-crafted focus states, instead of fighting the rule's
!important/specificity locally. Supersedes the previous outline:none
attempt, which didn't target the actual animation.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(sidecar): allow configuring the resizable button className

Add an optional className prop to ResizableButton, and forward it from
a new classNameButton option on OverlaySidecarOpenOptions/Sidecar, so
callers of overlays.sidecar.open() can style/opt-out the resizer
button (e.g. pass "osd-resetFocusState" to drop the global focus-ring
animation) without hardcoding it in the component.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Change top bar health-check icon (#1505)

* feat: update health check indicator

* Change top bar health-check icon to a pulse shown only when attention is needed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(core): use kebab-case for sidecar docked-mode CSS variable

Rename --osdSidecarSize to --osd-sidecar-size and switch attribute
selectors to double quotes to satisfy the repo's stylelint rules
(custom-property-pattern, string-quotes), registering sidecar.scss
in the global selectors allowlist for its .euiFlyout references.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* chore: use constant

* Rework health-check popover

* Rework health-check popover

* List failing health checks in the nav-button popover

Show the enabled non-green checks as an EuiHealth list in the health-check
popover, labelled by the check name and with the error surfaced in a tooltip.
Use the shared mapTaskStatusToHealthColor helper and TASK.RUN_RESULT constants
instead of magic strings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Fix popover closes when clicking inside

* Close popover after navigating to the health check

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Bump 5.0.0 branch (#1513)

feat: bump 5.0.0

* Fix RPM changelog entry order causing build failure (#1516)

Fix RPM changelog entry order for 5.0.0

The 5.0.0 changelog entry was placed out of descending chronological
order, causing rpmbuild to fail while parsing %changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1517)

Remove unnecessary debhelper install-time dependency (#1484)

fix: remove unnecessary debhelper install-time dependency

debhelper is only required to build the .deb package (declared under
Build-Depends in dev-tools/build-packages/deb/debian/control), not to
install a pre-built one. Remove it from the apt-get install steps used
to test package install/upgrade.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1537)

Merge 4.14.9 into 5.0.0: no changes (verified 2026-08-28)

* fix: remove inert opensearch_security.cookie.ttl setting (#1534)

The dashboard config declares opensearch_security.cookie.ttl, but the
security plugin never reads it: only opensearch_security.session.ttl
governs session/cookie expiry. Shipping the setting misleads operators
into believing it bounds the cookie lifetime.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Bump 5.0.0 branch (#1545)

feat: bump 5.0.0

* Revert bump 5.0.0 branch (#1546)

feat: revert 5.0.0 references

* Fix changelog not in descending chronological order (#1548)

* fix: keep RPM changelog entries in descending date order on re-bump (#1549)

Re-bumping an existing version updated its date in place instead of
repositioning it, so a newer date could end up below older entries and
rpmbuild rejected the spec (%changelog not in descending chronological
order). The entry is now removed and reinserted at the position
matching its date.

Also fixes date/sed portability on macOS (BSD date/sed vs GNU), and
makes an invalid date abort the script instead of writing the error
text into the changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Bump 5.0.0 branch (#1551)

feat: bump 5.0.0

* Review the 5.0.0 changelog (#1556)

* docs(changelog): review the 5.0.0 entries

Removed the open redirect fix entry (#1285) and the pre install script
check entry (#1328, #1365).

Reordered the sections to Added, Changed, Removed, Fixed, and qualified
the two wazuh-dashboard-plugins references so they no longer read as
wazuh-dashboard issues.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): reference issues instead of pull requests

Each entry now links the issue the pull request closed, so the reference
carries the description and the discussion instead of just the diff.

Where an entry listed several references that resolve the same issue, it
collapses to that one; where they resolve different issues, the entry
keeps the main one and the rest are attached to it as sub-issues on
GitHub, following the shape of wazuh-dashboard-plugins#8789.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): merge the health check service and app entries

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* docs(changelog): point the health check entry at its parent issue

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1563)

Merge 4.14.8 into 4.14.9 (#1562)

Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x
# Conflicts:
#	dev-tools/build-dev-image/README.md
#	dev-tools/build-dev-image/build-multiarch.sh
#	dev-tools/build-dev-image/install-plugins.sh
#	dev-tools/build-dev-image/plugins
#	dev-tools/build-dev-image/warmup-opensearch_dashboards.yml
#	dev-tools/build-dev-image/warmup-optimizer.sh
#	dev-tools/build-dev-image/wzd.dockerfile

* Bump 5.0.0 branch (#1567)

feat: bump 5.0.0

* Bump 5.0.0 branch (#1571)

feat: bump 5.0.0

* Fix empty error message in dashboard save failure toast (#1573)

The danger toast shown when saving a dashboard fails interpolated
savedDashboard.message, a property that does not exist on the saved
object instance, so the message always rendered as
"Dashboard 'X' was not saved. Error:" with nothing after "Error:".

Use the caught error's message instead.

Closes #1568

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Show the root cause of the failure in the error toast full error modal (#1574)

The See the full error modal built its copyable block from caused_by, which
can hold a failure raised while the response itself was being built rather
than the failure that made the request fail: querying a field that is not
searchable reported a null_pointer_exception about reducePhase.aggregations
instead of the query_shard_exception the backend reports under root_cause.

The reason of the root cause is now shown inside the danger callout, under
the message of the error, and is stripped of URLs, IP addresses and
filesystem paths. The copyable block keeps the content it had on 5.0.0,
the client stack trace included.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Merge 4.14.9 into 5.0.0 (#1581)

Merge 4.14.8 into 4.14.9 (#1580)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Reorder rpm changelog

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>

* Merge 4.14.10 into 5.0.0 (#1602)

* Bump 4.14.10 branch (#1589)

feat: bump 4.14.10

* Merge 4.14.9 into 4.14.10 (#1601)

Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Let a health check task report red, and show that red in the overall status (#1595)

* feat: Add TaskResult so health check tasks report their own result status

A health check task could only resolve or throw, and the registration-time
`critical` flag decided whether a throw became yellow or red. Because that same
flag also decides whether a failure blocks startup, a task had no way to report
red without holding the dashboard behind the "server is not ready yet" screen.

A task may now resolve a branded `TaskResult` and pick its own result status.
`critical` is untouched and goes on deciding whether a red result blocks
startup, so the new reachable combination is a non-critical red: visible,
without blocking.

The result is branded with a registry symbol rather than detected structurally.
An existing task already resolves `{ status: 'ok' }` as its data, so a
structural guard would reinterpret plain task data as a status and drop the
payload.

Tasks that resolve or throw are unaffected. No existing task changes.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* fix: Respect the check own result when computing the health check overall status

computeOverallStatus decided the overall status only from the critical flag,
so a check reporting red landed on the header as yellow. Every check registered
by the Wazuh plugins is non critical, which capped the indicator at yellow and
made red unreachable.

The aggregation now returns red for any finished check whose result is red,
keeps escalating a non green critical check to red, and returns yellow for any
other non green result.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* fix: Type the health check task error property as string or null

`public error = null` made TypeScript infer the literal type `null`, so
assigning a TaskResult message broke `tsc -b tsconfig.refs.json` and the CI
bootstrap. The catch branch got away with the same assignment because a catch
binding is `any`.

`ITask['error']` is already `string | null`, which is what the property held
all along.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* docs: Drop the redundant health check changelog entry

The overall status aggregation was not fixing a defect users could reach. In
5.0.0 the only assignment of a red result sits behind `if (this.critical)`, so
a non-critical red does not exist and the old aggregation was equivalent to the
new one. That state is created by this branch, so the behaviour belongs to the
Added entry rather than to a separate Fixed one.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* change: Require health check tasks to return a task result

A task could resolve any value, which the platform stored as data and marked
green, or resolve a branded TaskResult. Two return shapes for one outcome, and
the plain one gave a task no way to say anything but green.

`TaskDefinition.run` now returns a TaskResult. A value that is not branded is
rejected at runtime as well, because the type does not reach a task written in
JavaScript, and a silent gray result would be worse than a loud failure.

Throwing is unchanged and stays the path for the unexpected.

BREAKING CHANGE: every registered task must return taskResult.ok, warning or
error. The tasks in wazuh-dashboard-plugins migrate alongside this.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* docs: Update the health check README for the task result contract

The README documented the semantics this branch inverts. It stated in six
places that the result color encodes criticality: red meant a critical failure
and yellow a non-critical one, and the summary went red only for a critical
task. That held while the only path to red was a throw from a critical task.

It also described the summary with the startup blocking rule. Those are two
aggregations answering different questions, and only one of them changed, so
they are now documented apart.

The registration example returned nothing, which the new contract rejects.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Break word to prevent overflow

* change: Provide the result constructors in the health check task context

A task had to build its TaskResult itself, and core exported no constructor to
build one with. wazuh-dashboard-plugins answered that by hand-rolling a mirror
of the contract, relying on Symbol.for to resolve to the same brand. A required
contract nobody can import is a contract everybody copies.

The context a task already receives now carries the constructors, so a task
reports a result without importing anything. TaskRunContext replaces the `any`
the run parameter used to be, and the contract types are exported by name,
closing the TODO that kept them private.

Suggested by @Desvelao in review.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* refactor: Remove the unused health check ITask from the common types

It declared `run` as returning a generic `Promise<Result>`, which contradicts
both the task contract and the `ITask` the server defines. Nothing imported it,
in this repo or in wazuh-dashboard-plugins.

The name still exists in the server task types, which is the one implemented.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* change: Export the health check task contract from the server entry point

A plugin registering a check could not import TaskDefinition, TaskRunContext,
TaskResult or TaskResultFactory from src/core/server, so it redeclared them.
They are exported there now.

The manager annotates the context it passes, so the compiler checks that the
injected constructors reach the task.

The README interface block now matches the type: run receives a TaskRunContext,
critical is optional, and there is no index signature for extra fields.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

---------

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* feat(core): configurable version, help menu links, and an About page (#1609)

* feat(core): add configurable version, help menu links, and an About page

- opensearchDashboards.branding.applicationVersion overrides the version
  shown in the About page and the persistent help-menu badge; falls back
  to the real build version.
- opensearchDashboards.branding.helpMenuLinks overrides the help menu's
  Documentation/Slack/GitHub/Google Group list (replaces it entirely when
  set); each entry supports an optional darkModeIcon.
- New src/plugins/about core plugin hosts the About page (moved out of
  wazuh-dashboard-plugins), with its own about.communityLinks setting
  (same {label, link, icon, darkModeIcon} shape, hides the Community
  panel when set to an empty list), registered under the same "Dashboard
  management" category/position the page had before the move.
- Synced the legacy Joi config schema (src/legacy/server/config/schema.js)
  with the new branding.* keys to fix a boot-time validation error.
- Registered the new "about" i18n namespace in src/.i18nrc.json.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): use the Wazuh copyright header on new about plugin files

The new files added for the about plugin and help_menu type used the
"Copyright OpenSearch Contributors" header template, reserved for
OpenSearch-authored files. These are wholly new, Wazuh-original files, so
per this fork's own convention (.eslintrc.js OSD_WAZUH header, "For new
files created by Wazuh Contributors") they should use "Copyright Wazuh"
instead.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs(changelog): add entries for the about plugin and branding settings

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): hide all help menu links when helpMenuLinks is empty

Treat opensearchDashboards.branding.helpMenuLinks as configured whenever it
is set, so an empty list renders no links instead of falling back to the
built-in ones, matching about.communityLinks and the documented behavior.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): register the About app in the all nav group

Add the About app to DEFAULT_NAV_GROUPS.all under the Dashboard
management category so it stays visible once the new navigation is
enabled. Previously it reached the nav group through the main plugin's
registerWazuhNavLinks, which no longer lists it after the move.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* fix(core): set the About page breadcrumb and document title

The About app never set its breadcrumb or document title, so the header
kept showing the previous app's breadcrumb (e.g. "Overview") and the tab
title stayed "Wazuh". Set both to "About" when the app mounts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Merge 4.14.10 into 5.0.0 (#1616)

Merge 4.14.9 into 4.14.10 (#1615)

* Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------




* Merge 4.14.8 into 4.14.9 (#1614)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

* Bump 4.14.8 branch (#1612)

feat: bump 4.14.8

---------




---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Resolve dashboard credentials at install and start (#1613)

* feat(packages): resolve dashboard credentials at install and start

Replace the hardcoded kibanaserver keystore pair and the plaintext
wazuh-wui password with the shared resolve-credentials script, run from
postinst/%post and from the unit's ExecStartPre=+. The script is
downloaded and checksum-verified at build time. Purge removes /etc/wazuh
only when no other Wazuh central component remains.

Closes #1594

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): ship the credentials resolver in the repo

Replace the build-time download of resolve-credentials with a script
maintained in this repository, adapted from the manager's resolver.
Only the shared wazuh-credentials.sh library is still downloaded at
build time, from wazuh-installation-assistant, into lib/.

The resolver takes --install, --upgrade, --prestart and --clear. The
maintainer scripts, the systemd unit and the SysV init script call it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): honour credentials set in the dashboard config

Treat opensearch.password and wazuh_core.hosts.default.password set in
opensearch_dashboards.yml as resolved, so the resolver neither refuses
the start nor writes keystore entries that would override the yml.
Never write opensearch.username over a user set in the yml, and skip
the wazuh-wui entry when the yml defines no default host.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): generate the AI assistant key in the resolver

Move the wazuh_ai_assistant.encryptionKey generation out of postinst
and %post into resolve-credentials. It is generated on --install and
--prestart when neither the keystore nor opensearch_dashboards.yml has
it, never on --upgrade, and never replaced. A generation failure only
warns. --clear now removes it too, so an image does not share one key
across containers.

The resolver already creates the keystore, so the maintainer scripts no
longer do.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): pick the credentials library ref from the build

Try an ordered list of wazuh-installation-assistant refs (override, tag
being built, branch being built, version branch, version tag) instead of
a single ref. A tag build only tries its tag.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): supply credentials before starting the service in CI

The unit now runs resolve-credentials --prestart, which refuses to start
while the kibanaserver and wazuh-wui passwords are unresolved. The DEB
install test started the service on a clean install with no credentials,
so the start failed.

Assert the refusal first, then write test credentials to
/etc/wazuh/credentials.env and start the service. Dump the unit journal
on failure.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): issue the dashboard TLS certificates from the shared CA

On a fresh install, resolve-credentials now issues dashboard.pem and
dashboard-key.pem, and installs root-ca.pem, into
/etc/wazuh-dashboard/certs from the shared Wazuh root CA (/etc/wazuh/ca).
The CA is created through the shared credentials library when no
component has created it yet, and reused otherwise.

An existing complete pair is kept, a partial pair is refused, and an
anchor-only CA cannot issue, so the operator is told to stage a pair.
--upgrade and --prestart never touch the certificates; --clear removes
them together with a CA minted on this host. Files are staged in a
root-only directory and published with ln -T, and each step is logged
with public data only.

The packages now depend on openssl (and diffutils and util-linux on
RPM), which the issuance and the shared library need.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs(packages): reference the manager's certificate issuance

Point the dashboard certificate step and its README to the manager's
issue and PR it mirrors: wazuh/wazuh#39554 and wazuh/wazuh#39571.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* revert: reference the manager's certificate issuance

This reverts commit e9bde535c6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): supply credentials before starting the service in RPM CI

The unit runs resolve-credentials --prestart, which refuses to start while
the kibanaserver and wazuh-wui passwords are unresolved. The RPM install
test still started the service on a clean install with no credentials, so
the start failed (run 36148424354).

Move the inline SSH test into rpm-test-install-uninstall.sh, mirroring the
DEB test: check the issued certificates, assert the refusal, write test
credentials to /etc/wazuh/credentials.env, start the service and dump the
unit journal on failure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): only reject passwords the keystore would not store verbatim

resolve-credentials validated the consumed kibanaserver and wazuh-wui
passwords against the shared password policy. That policy is fetched
unpinned from wazuh-installation-assistant and has since gained a symbol
requirement, so the CI test passwords were rejected and the service did
not start (run 36389268794). The dashboard's own message already
described an older version of the rule.

The indexer and the manager own these passwords and enforce the policy.
The dashboard now checks only what is its own concern: keystore add
trims the value and stores it JSON.parse'd, so reject any value it would
not store verbatim (JSON numbers, booleans, quoted strings, arrays,
objects, surrounding whitespace). The check repeats add.js with the
bundled Node.

Add a negative case to the DEB and RPM install tests asserting that a
JSON number is reported as INVALID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): add a VM test matrix for install and start

vm-test-matrix.sh runs 21 cases against a built .deb or .rpm on a
disposable VM: fresh install, credentials from credentials.env, the
environment and the yml, invalid values, a refused credentials file,
shared CA reuse, anchor-only CA, operator and partial certificate pairs,
custom SANs, --clear, removal, reinstall and, with --previous, upgrades.
The host is wiped after every case and a summary is printed.
--clean-only wipes the host without running a case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): cover install orders with the manager and indexer

Rename --package and --previous to --dashboard and --dashboard-previous,
and add --manager and --indexer. Dashboard-only cases are now D01-D21;
the new F01-F08 cases need both sibling packages and run only when they
are given.

F01-F06 install the indexer, the manager and the dashboard in every
order and check after each step that the dashboard resolves exactly
what credentials.env holds, names what it lacks, refuses to start until
both keys are resolved, and reuses or mints the shared CA. F07 purges
the dashboard with the siblings still installed; F08 reinstalls it. The
siblings' own start and CA are recorded as [INFO].

Cleanup purges wazuh-manager and wazuh-indexer too when their packages
are given, or with --force.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): let the service group read the shared credentials library

At startup OSD's i18n loader globs */.i18nrc.json under the installation
root, which lists every top-level directory. lib/ was root:root 0750, so
the wazuh-dashboard user got EACCES on scandir and the server exited with
a fatal error.

Keep lib/ and wazuh-credentials.sh owned by root, so the service user
still cannot modify what ExecStartPre=+ sources as root, but give them
the wazuh-dashboard group (0750 / 0640) so the loader can list the
directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): read the keystore before grepping it in CI

`keystore list | grep -q` under `pipefail` failed when grep closed the
pipe on the first match and the keystore CLI hit EPIPE, reporting the AI
assistant key as missing although it was present (RPM aarch64).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Check Prettier only on the lines a change writes (#1608)

* fix(ci): check Prettier only on the lines a change writes

The check runs over every file a change touches. Most of this repository
comes from OpenSearch Dashboards, which never ran Prettier over its own
tree, so changing two lines in a file that was never formatted demands a
reformat of the whole file. On wazuh/wazuh-dashboard-alerting#148 that was
318 lines of rewriting to land 400 lines of work.

No configuration fixes this. Sweeping nine Prettier versions from 1.19.1 to
3.6.2 and every single-option change against upstream's own `.prettierrc`
leaves a floor of 73 of 670 source files failing. There is nothing to align
to.

Rewriting those files is what costs us. Each one diverges from its
counterpart on the other version branches, so the next upward merge or
cherry-pick conflicts, and the next OpenSearch migration replays a larger
Wazuh delta onto the new upstream tree.

So a change answers for the lines it writes and nothing else. A file it adds
is checked in full; a line it did not touch is not checked.

`scripts/prettier-check-changed.js` compares what the change wrote against
what Prettier wants and reports the overlap. `--fix` corrects those lines
and leaves the rest of the file alone. A merge branch passes the branch
being merged as a second base, so lines that exist in either parent are not
the merge's own. The pre-commit hook returns early during a merge,
cherry-pick, revert or rebase, where it was blocking
`git cherry-pick --continue` during the scheduled merges.

Backtested over 43 merged pull requests across the six repositories it
spares 28 of 29 files, with no false positives.

Refs wazuh/wazuh-dashboard#1605

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(ci): compare against the merge base and follow renames

Three problems found in review.

The check diffed against the tip of the base branch. When the base moves
ahead after a pull request branches off, that diff also reports the base's
own later commits, in reverse, and blames them on the change. A pull request
that adds one line was asked to reformat a line the base had already fixed.
Resolve each base with `git merge-base <ref> HEAD` instead, which is what
GitHub uses for "Files changed", so the check and the diff a reviewer reads
agree. The workflow needs the shared history for that, so the checkout takes
`fetch-depth: 0`.

A renamed file was checked in full. Git cannot pair a rename when the diff
receives only the new path, so it reported the file as added. Pass both paths.
The rename map was also built against the first base alone, so with two bases
the second lookup missed and the file looked new again; build one map per
base. Any upward merge carrying a rename hit this.

The `--fix` hint named `scripts/`, which is wrong in `wazuh-dashboard` where
the script lives in `dev-tools/`. Derive the path from the running script.

Refs wazuh/wazuh-dashboard#1605

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Fix --clear removing a CA it did not mint, and RPM ownership of a pre-staged certificate pair (#1621)

* fix(packages): only clear a shared CA the dashboard minted

--clear removed the shared root CA whenever root-ca.key existed, which also
destroys an operator-staged signing CA. Record the mint with
.wazuh-dashboard-bootstrap-ca under the credentials lock, as the manager does
with .wazuh-manager-bootstrap-ca, and delete the CA only when that marker is
present. Also remove staging directories an interrupted issue left behind,
and refuse a non-root --clear instead of reporting a clear that did not happen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): give a pre-staged certificate pair to the service user on RPM

A pair staged into /etc/wazuh-dashboard/certs before the package is
installed (e.g. by the installation assistant) is root:root, because the
service user does not exist yet. The resolver keeps an existing pair as it
finds it, so on RPM the service failed with EACCES reading
dashboard-key.pem. DEB was unaffected: its postinst already runs chown -R
on the configuration directory before the resolver.

Chown certs/ to wazuh-dashboard in %post before the resolver, on install
and upgrade, as the indexer and the manager do in their packaging. D13 now
checks the ownership and starts the service with the staged pair.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* Stop the service user from running code as root through the packages (#1620)

* build(packages): install /usr/share/wazuh-dashboard as root:root

The deb and rpm packages installed the whole installation directory as
wazuh-dashboard:wazuh-dashboard, so the service user could replace the code
that root runs from ExecStartPre=+ (bin/resolve-credentials, lib/, node/).
The directory is now root:root, with directories and executables at 755 and
other files at 644. data/ stays wazuh-dashboard:wazuh-dashboard 750 because
the dashboard writes to it at runtime. /etc/wazuh-dashboard is unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): keep root from trusting the service user's environment

/etc/default/wazuh-dashboard was owned by the service user, but root reads
it at every start: systemd passes it to ExecStartPre=+ through
EnvironmentFile=, and the SysV script sources it. The service user could
therefore choose what resolve-credentials ran as root.

- Install /etc/default/wazuh-dashboard as root:wazuh-dashboard 0640, and
  fix its ownership on upgrade in postinst and %post.
- When run as root, resolve-credentials sets a fixed PATH and unsets
  LD_PRELOAD, LD_LIBRARY_PATH and NODE_OPTIONS.
- Read wazuh-credentials.sh only from lib/ of the installation directory:
  drop the WAZUH_SHARED_HELPER_DIR override and the copy next to the script.
  The error now names the expected path.
- Run the node call in keystore_stores_verbatim as the service user.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Make the dashboard keystore readable only by its owner (#1622)

The keystore is encrypted with an empty password, so its file mode is the
only thing keeping the secrets private. It was written with the default
mode (0644 under a 022 umask), readable by every local user once the
parent directory protection is relaxed or bypassed.

Keystore.save() now creates the file with mode 0600 and restricts an
existing file before writing to it. Every writer goes through it: the
keystore CLI, and so the credentials resolver at install and pre-start.
The deb postinst and rpm %post also enforce 0600 and wazuh-dashboard
ownership on every install, so keystores created by earlier packages are
fixed on upgrade. The package install tests check the mode.

Closes #1619

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Fix the 5.x dev Docker image workflow and make plugin branches resolvable (#1593)

* Fix the 5.x dev Docker image workflow and make plugin branches resolvable

Start the Docker daemon on the AWS CodeBuild runners instead of pruning a
daemon that is not running, which aborted every scheduled run. Reduce the
schedule to a weekly build, add a plugins_branch input that falls back per
repository to the branch the workflow runs on when the branch does not exist
there, check out the requested branch in the build job, and let the inputs
default to the versions in package.json and .nvmrc.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Authenticate against Docker Hub before building the dev image

The build failed pulling node:22.22.0 with a 429 Too Many Requests: the AWS
CodeBuild runners share an IP pool that exhausts the Docker Hub anonymous pull
limit. Log in with the credentials the other build workflows already use.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Add diagnostics to the dev image build job

The build job died after 69 minutes with the build step still in progress and
no archived logs, so the failure cannot be read. Cap the job below the runner
reclaim window so GitHub stops it and keeps the logs, print the build with
plain progress, report memory, disk and kernel OOM kills after the step, and
stop the matrix from cancelling the sibling architecture.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Fall back to main when the workflow branch is missing in a plugin repository

The existence check only ran when plugins_branch was provided, so a run from a
branch of this repository that the plugin repositories do not have cloned a
non-existent branch. Walk the candidates in order - requested branch, workflow
branch, main - and use the first one that exists in each repository.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Raise the dev image build timeout to 90 minutes

With logs archived the build proved to need ~55 minutes of layers - 36 of them
in the optimizer warmup - plus the push to Quay.io, and it reports no OOM kills
and 100G of free disk. Give the job room to finish instead of cutting it in the
middle of the push.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Stop forcing the vfs storage driver on the Docker daemon

On the arm64 runner the daemon we start is the one that serves the build, and
vfs copies the whole filesystem on every layer: WORKDIR took 97s and a 1 KB
COPY took 19 minutes, against 0.2s and 0.1s on amd64, where a pre-existing
daemon on overlay2 answered instead. Reuse the running daemon when there is
one, let dockerd pick its driver otherwise, and keep vfs only as a fallback.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Pick the Docker storage driver by probing overlay stacking

Letting dockerd choose broke the arm64 job: it picked overlayfs and then failed
to mount, because / is an overlay mount on that runner and overlay does not
stack. Probe an overlay mount first, use the default driver when it works, try
fuse-overlayfs when it does not, and keep vfs as the last resort.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Build the dev image in a single expensive layer

Runners whose root filesystem is an overlay mount cannot stack overlay and fall
back to the vfs storage driver, which copies the whole tree on every layer.
Once /home/node/kbn holds node_modules that is about 19 minutes per layer, and
the checkout was followed by six of them - two WORKDIR, three COPY and two RUN
- which is over an hour of pure copying on the arm64 runner and free on amd64.
Copy the scripts before the checkout, where the tree is still empty, and run
the bootstrap, the plugin install and the optimizer warmup in one layer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Keep the image build output as an artifact

GitHub does not archive the log of a job it cancels, and the arm64 job is
cancelled by the timeout on every run, so three runs in a row left no trace of
which storage driver was chosen or how long each layer took. Tee the build
output to a file and upload it even when the step fails.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Drop the second stage of the dev image build

The stage existed to keep the intermediate layers out of the pushed image, but
the build is a single layer now and there is nothing left to drop. All it did
was copy /home/node/kbn in full - 320s on amd64, another whole-tree copy under
vfs - and chown every file in node_modules, which the git clone had already
created as node.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Raise the build timeout to 115 minutes

The CodeBuild runners now allow 120 minutes, but the job kept being cut at 90
by the workflow's own timeout, which was the lower of the two. Leave a margin
below the runner limit so GitHub is the one that stops a build that does not
finish, and the build log is uploaded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Set the build timeout to 120 minutes

Match the limit the CodeBuild runners now allow.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

---------

Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Diego García <82405377+Ripdiegozz@users.noreply.github.com>

* Keep the service user out of root's credential resolver paths (#1623)

The resolver runs as root from the maintainer scripts and ExecStartPre=+,
while /etc/wazuh-dashboard belongs to the service user. Three paths still
let that user steer root:

- --clear deleted dashboard.pem, dashboard-key.pem and root-ca.pem through
  the absolute ${CERTS_DIR} path, so a certs/ replaced with a symlink made
  root delete those names wherever it pointed, e.g. the shared CA anchor.
  It now enters certs/ as the issuing path does, removes relative to it,
  and refuses (and fails) when certs/ is not a real directory.

- The SAN list was written and read back through $(pwd -P)/<stage>/sans,
  which is resolved again through certs/ on each use. Swapping certs/
  between the two let the service user choose the names the shared CA
  signs. It is now built inside _dc_issue_pair, relative to the verified
  root-only staging directory.

- runuser kept the keystore and Node children in root's session and
  environment: from an interactive dpkg/rpm they could open root's
  terminal (TIOCSTI) and read what root exported, credentials included.
  Every child now goes through as_service_user: setsid (-w where
  util-linux has it) and env -i with only PATH and OSD_PATH_CONF.

The VM test matrix gains D22 (--clear with a symlinked certs/) and D23
(a node.options probe run from a terminal sees no tty and no root env).

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Restrict the not-ready healthcheck API to critical tasks and hide task data (#1624)

* Restrict the not-ready healthcheck API to critical tasks and hide task data

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Hide non-critical task errors on the not-ready server and escape the page output

- Replace the error of tasks that are not enabled and critical with a generic message, because it can carry node names and certificate details.
- Sort and dedupe the requested task names so reordered or repeated names share one run.
- Escape task names and errors on the not-ready page.
- Make the route test mocks return real task results so the checks exercise stored data.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Hand the kept configuration over to root on RPM removal (#1625)

Removing the RPM package deletes the wazuh-dashboard user and group but
keeps /etc/wazuh-dashboard, whose certificates, private keys and keystore
stayed owned by the freed UID and GID. The next system account created
could inherit them and read those secrets.

Before the account goes, %postun now makes root the owner of everything
the account or its group owns in /etc/wazuh-dashboard, strips group and
other access, and reports what it kept, as the Wazuh indexer package
does. A kept /etc/default/wazuh-dashboard.rpmsave loses the group too.
A fresh install takes the directory back. The package test checks both.

Related: wazuh/wazuh-dashboard-plugins#9257

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Merge 4.14.10 into 5.0.0 (#1635)

Merge 4.14.9 into 4.14.10 (#1634)

* Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------




* Merge 4.14.8 into 4.14.9 (#1614)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

* Bump 4.14.8 branch (#1612)

feat: bump 4.14.8

---------




* Bump 4.14.9 branch (#1627)

feat: bump 4.14.9

* Change tag reference for 4.14.9 (#1629)

chore(tag-reference): change tag reference for 4.14.9

---------

Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>

* Fix Indexer management and Dashboards Management menu paths in docs (#1636)

* docs: fix Indexer management menu name on the read-only mode page

The read-only mode page named a Management menu that does not exist
in 5.0; the top-level category for indexer administration is Indexer
management (src/core/utils/default_app_categories.ts:76-82).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs: replace nonexistent Stack Management entry in Discover guide

getting_started_with_discover.md pointed to a 'Stack Management'
sidebar entry that doesn't exist in the Wazuh dashboard. The app is
titled Dashboards Management, under the Dashboard management category
(src/plugins/management/public/plugin.ts:84-86), with Data sources
(src/plugins/data_source_management/common/index.ts) as one of its
sections. Fix the same wrong label in the dsm_flow.puml diagram.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs: address review feedback on dashboard menu paths

- Rewrite the Discover data selector sub-steps as a real nested list;
  the plain a.-d. lines rendered as a lazy continuation of the S3 bullet.
- Drop the nonexistent "☰" label from the Dashboards Management path and
  note that the Wazuh dashboard hard-disables home:useNewHomePage, so the
  classic navigation always applies.
- Align the workspace "Data sources" tab casing.
- Replace the leftover "stack management" mention in user_stories.md.
- Rename the stale Page-Stack alias in dsm_flow.puml and regenerate
  dsm_flow.png from it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Fix the not-ready page false success notice (#1640)

* Show the not-ready success notice only after checks

The not ready page reported that no critical errors remain while the
health checks had not run yet, because only enabled, finished and failed
tasks counted. Show the success notice only once enabled tasks finished,
and a generic waiting notice otherwise.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Log the cause of bodyless indexer response errors

Responses without an OpenSearch error object, such as the security
plugin answering 503 or 401 with plain text, were logged as
"Response Error". Include the status code, the request method and path
and the bounded plain-text body so the cause shows in the server log.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Reword the not-ready waiting notice

The page cannot tell why the health checks have no results yet: the server may be waiting for the indexer, running saved object migrations or running the checks. State only that, and point to the logs.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Mark the Wazuh changes in the OpenSearch client

configure_client.ts and its test come from OpenSearch Dashboards. Keep the original code commented out and tag each Wazuh addition.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Fix the type of the bounded log line test

The collected log entry is typed string | Error, so reading .length broke the TypeScript project build (tsc -b tsconfig.refs.json) in the bootstrap step.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

---------

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* End the package install with how to log in (#1639)

feat(packages): end the install with how to log in

Print the dashboard URL, the admin login and the start command at the end of a fresh install. Show the certificate detail only with WAZUH_DASHBOARD_VERBOSE=1.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Bump 5.0.0 branch (#1645)

feat: bump 5.0.0

* Revert bump 5.0.0 branch (#1647)

feat: revert 5.0.0 references

* Bump 5.0.0 branch (#1650)

feat: bump 5.0.0

* Name the browser tab after the current app and add a skip link (#1643)

* fix(chrome): name the browser tab after the current app

Set the tab title to "<app title> - <applicationTitle>" on every app change instead of resetting it to the base title, so every plugin's app gets a distinct title. Fall back to Wazuh instead of OpenSearch Dashboards when applicationTitle is invalid.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* feat(rendering): add a skip to main content link

Render a skip link before the header, hidden until focused with Tab. Enter moves focus to the app wrapper without changing the URL hash, which the apps use for routing. Not rendered while the header is hidden, such as on the login page.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>

* Fix Timeline label regex blocking the server (#1652)

fix(timeline): run .label() regex with re2js to avoid ReDoS

A user-supplied .label() regex ran on native RegExp, so a nested quantifier could block the server's event loop. re2js runs in linear time and rejects backreferences and lookarounds.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Minify the production bundles (#1646)

* feat(optimizer): minify the production bundles

Enable SWC compress and mangle for the optimizer bundles, which were
shipped with both disabled since the fork from Kibana.

Keep class and function names: code reads constructor.name (error
messages, error boundaries), and Babel compiles our classes to
functions, so keep_classnames alone does not protect them.

On a local amd64 package built from the same commits as the CI one,
the entry bundles shrink 38% decoded and 26% brotli, and the deb 3.3%.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* test(optimizer): update the dist bundle snapshot

The production bundles are now compressed and mangled, so the dist
snapshot of the foo and bar fixture bundles holds the minified code.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

---------

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Disable and reload the wazuh-dashboard systemd unit on RPM and DEB removal (#1654)

* fix(packaging): disable wazuh-dashboard systemd unit on RPM removal

systemctl stop in the %preun scriptlet left the unit enabled, leaving a
dangling multi-user.target.wants symlink and a not-found unit once the
RPM deleted the unit file. Mirror the DEB prerm and the wazuh-indexer
RPM by also running systemctl --no-reload disable before removal.

Closes #1653

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packaging): mirror the indexer's stop/disable/reload sequence in the RPM and DEB packages

The RPM %preun already stops and disables the unit, but nothing told
systemd to forget it once the unit file was actually removed, so
systemctl list-units could keep reporting it as not-found until some
unrelated reload happened. The DEB prerm disabled the unit without
--no-reload, and its postrm never reloaded either. Add the matching
daemon-reload to %postun/postrm, and --no-reload to the DEB disable
call, exactly as the wazuh-indexer RPM and DEB packages already do.

Closes #1653

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packaging): add --no-reload to the RPM stop call, matching the indexer

The DEB prerm and the wazuh-indexer RPM both suppress the reload on
stop since disable (right after) reloads once anyway; the dashboard
RPM's stop call was missing that flag.

Closes #1653

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packaging): add --no-reload to the RPM's upgrade stop call too

%pre stops the running service before an in-place upgrade, same as
%preun does before removal. The wazuh-indexer RPM suppresses the
reload there too, since the unit file isn't changing yet.

Closes #1653

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Rename wazuh-wui to wazuh-internal-client (#1651)

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Configura CA validation by default (#1660)

* Merge 4.14.10 into 5.0.0 (#1671)

Merge 4.14.9 into 4.14.10 (#1664)

* Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------




* Merge 4.14.8 into 4.14.9 (#1614)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

* Bump 4.14.8 branch (#1612)

feat: bump 4.14.8

---------




* Bump 4.14.9 branch (#1627)

feat: bump 4.14.9

* Change tag reference for 4.14.9 (#1629)

chore(tag-reference): change tag reference for 4.14.9

* Bump 4.14.9 branch (#1656)

feat: bump 4.14.9

* Change tag reference for 4.14.9 (#1657)

chore(tag-reference): change tag reference for 4.14.9

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>

* Merge 4.14.11 into 5.0.0 (#1686)

Bump 4.14.11 branch (#1663)

feat: bump 4.14.11

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>
Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Rodrigo López <37187963+rodrigofez@users.noreply.github.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Diego García <82405377+Ripdiegozz@users.noreply.github.com>
* Report skipped bumps in the repository bumper workflow (#1492)

Improve repository bumper error handling

* Recalculate flyout position when the sidecar is opened (#1503)

* Adapt flyout position in relation to the sidecar

* Add changelog

* Change resizable button emphasis style from :focus to :active (#1508)

* fix(sidecar): change resizable button emphasis style from :focus to :active

Update the .sidecar-resizableButton CSS to emphasize the "grab" icon
on :active instead of :focus, matching the intended interaction
feedback when dragging the resizer.

Closes https://github.com/wazuh/wazuh-dashboard-plugins/issues/8989

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): remove leftover native focus outline on resizable button

The resizable button programmatically calls .focus() on every click,
so after removing the custom :focus emphasis in favor of :active, the
browser's default focus outline was left showing as an unstyled
colored border until focus moved elsewhere. Suppress it for
mouse/touch interaction while keeping it for keyboard users via
:focus-visible.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): opt out resizable button from the global focus-ring animation

The resizable button programmatically calls .focus() on every click,
which triggered OSD's global brute-force focus-ring animation
(:focus:not([class^="eui"]):not(.osd-resetFocusState) in _base.scss)
since the button isn't an EUI component. That showed as a lingering
colored border after dragging, independent from the button's own
:active styling. Opt out via the "osd-resetFocusState" class, which is
the mechanism _base.scss already documents for components with
hand-crafted focus states, instead of fighting the rule's
!important/specificity locally. Supersedes the previous outline:none
attempt, which didn't target the actual animation.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(sidecar): allow configuring the resizable button className

Add an optional className prop to ResizableButton, and forward it from
a new classNameButton option on OverlaySidecarOpenOptions/Sidecar, so
callers of overlays.sidecar.open() can style/opt-out the resizer
button (e.g. pass "osd-resetFocusState" to drop the global focus-ring
animation) without hardcoding it in the component.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Change top bar health-check icon (#1505)

* feat: update health check indicator

* Change top bar health-check icon to a pulse shown only when attention is needed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(core): use kebab-case for sidecar docked-mode CSS variable

Rename --osdSidecarSize to --osd-sidecar-size and switch attribute
selectors to double quotes to satisfy the repo's stylelint rules
(custom-property-pattern, string-quotes), registering sidecar.scss
in the global selectors allowlist for its .euiFlyout references.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* chore: use constant

* Rework health-check popover

* Rework health-check popover

* List failing health checks in the nav-button popover

Show the enabled non-green checks as an EuiHealth list in the health-check
popover, labelled by the check name and with the error surfaced in a tooltip.
Use the shared mapTaskStatusToHealthColor helper and TASK.RUN_RESULT constants
instead of magic strings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Fix popover closes when clicking inside

* Close popover after navigating to the health check

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Bump 5.0.0 branch (#1513)

feat: bump 5.0.0

* Fix RPM changelog entry order causing build failure (#1516)

Fix RPM changelog entry order for 5.0.0

The 5.0.0 changelog entry was placed out of descending chronological
order, causing rpmbuild to fail while parsing %changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1517)

Remove unnecessary debhelper install-time dependency (#1484)

fix: remove unnecessary debhelper install-time dependency

debhelper is only required to build the .deb package (declared under
Build-Depends in dev-tools/build-packages/deb/debian/control), not to
install a pre-built one. Remove it from the apt-get install steps used
to test package install/upgrade.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1537)

Merge 4.14.9 into 5.0.0: no changes (verified 2026-08-28)

* fix: remove inert opensearch_security.cookie.ttl setting (#1534)

The dashboard config declares opensearch_security.cookie.ttl, but the
security plugin never reads it: only opensearch_security.session.ttl
governs session/cookie expiry. Shipping the setting misleads operators
into believing it bounds the cookie lifetime.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Bump 5.0.0 branch (#1545)

feat: bump 5.0.0

* Revert bump 5.0.0 branch (#1546)

feat: revert 5.0.0 references

* Fix changelog not in descending chronological order (#1548)

* fix: keep RPM changelog entries in descending date order on re-bump (#1549)

Re-bumping an existing version updated its date in place instead of
repositioning it, so a newer date could end up below older entries and
rpmbuild rejected the spec (%changelog not in descending chronological
order). The entry is now removed and reinserted at the position
matching its date.

Also fixes date/sed portability on macOS (BSD date/sed vs GNU), and
makes an invalid date abort the script instead of writing the error
text into the changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Bump 5.0.0 branch (#1551)

feat: bump 5.0.0

* Review the 5.0.0 changelog (#1556)

* docs(changelog): review the 5.0.0 entries

Removed the open redirect fix entry (#1285) and the pre install script
check entry (#1328, #1365).

Reordered the sections to Added, Changed, Removed, Fixed, and qualified
the two wazuh-dashboard-plugins references so they no longer read as
wazuh-dashboard issues.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): reference issues instead of pull requests

Each entry now links the issue the pull request closed, so the reference
carries the description and the discussion instead of just the diff.

Where an entry listed several references that resolve the same issue, it
collapses to that one; where they resolve different issues, the entry
keeps the main one and the rest are attached to it as sub-issues on
GitHub, following the shape of wazuh-dashboard-plugins#8789.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): merge the health check service and app entries

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* docs(changelog): point the health check entry at its parent issue

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1563)

Merge 4.14.8 into 4.14.9 (#1562)

Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x
# Conflicts:
#	dev-tools/build-dev-image/README.md
#	dev-tools/build-dev-image/build-multiarch.sh
#	dev-tools/build-dev-image/install-plugins.sh
#	dev-tools/build-dev-image/plugins
#	dev-tools/build-dev-image/warmup-opensearch_dashboards.yml
#	dev-tools/build-dev-image/warmup-optimizer.sh
#	dev-tools/build-dev-image/wzd.dockerfile

* Bump 5.0.0 branch (#1567)

feat: bump 5.0.0

* Bump 5.0.0 branch (#1571)

feat: bump 5.0.0

* Fix empty error message in dashboard save failure toast (#1573)

The danger toast shown when saving a dashboard fails interpolated
savedDashboard.message, a property that does not exist on the saved
object instance, so the message always rendered as
"Dashboard 'X' was not saved. Error:" with nothing after "Error:".

Use the caught error's message instead.

Closes #1568

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Show the root cause of the failure in the error toast full error modal (#1574)

The See the full error modal built its copyable block from caused_by, which
can hold a failure raised while the response itself was being built rather
than the failure that made the request fail: querying a field that is not
searchable reported a null_pointer_exception about reducePhase.aggregations
instead of the query_shard_exception the backend reports under root_cause.

The reason of the root cause is now shown inside the danger callout, under
the message of the error, and is stripped of URLs, IP addresses and
filesystem paths. The copyable block keeps the content it had on 5.0.0,
the client stack trace included.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Merge 4.14.9 into 5.0.0 (#1581)

Merge 4.14.8 into 4.14.9 (#1580)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Reorder rpm changelog

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>

* Merge 4.14.10 into 5.0.0 (#1602)

* Bump 4.14.10 branch (#1589)

feat: bump 4.14.10

* Merge 4.14.9 into 4.14.10 (#1601)

Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Let a health check task report red, and show that red in the overall status (#1595)

* feat: Add TaskResult so health check tasks report their own result status

A health check task could only resolve or throw, and the registration-time
`critical` flag decided whether a throw became yellow or red. Because that same
flag also decides whether a failure blocks startup, a task had no way to report
red without holding the dashboard behind the "server is not ready yet" screen.

A task may now resolve a branded `TaskResult` and pick its own result status.
`critical` is untouched and goes on deciding whether a red result blocks
startup, so the new reachable combination is a non-critical red: visible,
without blocking.

The result is branded with a registry symbol rather than detected structurally.
An existing task already resolves `{ status: 'ok' }` as its data, so a
structural guard would reinterpret plain task data as a status and drop the
payload.

Tasks that resolve or throw are unaffected. No existing task changes.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* fix: Respect the check own result when computing the health check overall status

computeOverallStatus decided the overall status only from the critical flag,
so a check reporting red landed on the header as yellow. Every check registered
by the Wazuh plugins is non critical, which capped the indicator at yellow and
made red unreachable.

The aggregation now returns red for any finished check whose result is red,
keeps escalating a non green critical check to red, and returns yellow for any
other non green result.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* fix: Type the health check task error property as string or null

`public error = null` made TypeScript infer the literal type `null`, so
assigning a TaskResult message broke `tsc -b tsconfig.refs.json` and the CI
bootstrap. The catch branch got away with the same assignment because a catch
binding is `any`.

`ITask['error']` is already `string | null`, which is what the property held
all along.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* docs: Drop the redundant health check changelog entry

The overall status aggregation was not fixing a defect users could reach. In
5.0.0 the only assignment of a red result sits behind `if (this.critical)`, so
a non-critical red does not exist and the old aggregation was equivalent to the
new one. That state is created by this branch, so the behaviour belongs to the
Added entry rather than to a separate Fixed one.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* change: Require health check tasks to return a task result

A task could resolve any value, which the platform stored as data and marked
green, or resolve a branded TaskResult. Two return shapes for one outcome, and
the plain one gave a task no way to say anything but green.

`TaskDefinition.run` now returns a TaskResult. A value that is not branded is
rejected at runtime as well, because the type does not reach a task written in
JavaScript, and a silent gray result would be worse than a loud failure.

Throwing is unchanged and stays the path for the unexpected.

BREAKING CHANGE: every registered task must return taskResult.ok, warning or
error. The tasks in wazuh-dashboard-plugins migrate alongside this.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* docs: Update the health check README for the task result contract

The README documented the semantics this branch inverts. It stated in six
places that the result color encodes criticality: red meant a critical failure
and yellow a non-critical one, and the summary went red only for a critical
task. That held while the only path to red was a throw from a critical task.

It also described the summary with the startup blocking rule. Those are two
aggregations answering different questions, and only one of them changed, so
they are now documented apart.

The registration example returned nothing, which the new contract rejects.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Break word to prevent overflow

* change: Provide the result constructors in the health check task context

A task had to build its TaskResult itself, and core exported no constructor to
build one with. wazuh-dashboard-plugins answered that by hand-rolling a mirror
of the contract, relying on Symbol.for to resolve to the same brand. A required
contract nobody can import is a contract everybody copies.

The context a task already receives now carries the constructors, so a task
reports a result without importing anything. TaskRunContext replaces the `any`
the run parameter used to be, and the contract types are exported by name,
closing the TODO that kept them private.

Suggested by @Desvelao in review.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* refactor: Remove the unused health check ITask from the common types

It declared `run` as returning a generic `Promise<Result>`, which contradicts
both the task contract and the `ITask` the server defines. Nothing imported it,
in this repo or in wazuh-dashboard-plugins.

The name still exists in the server task types, which is the one implemented.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* change: Export the health check task contract from the server entry point

A plugin registering a check could not import TaskDefinition, TaskRunContext,
TaskResult or TaskResultFactory from src/core/server, so it redeclared them.
They are exported there now.

The manager annotates the context it passes, so the compiler checks that the
injected constructors reach the task.

The README interface block now matches the type: run receives a TaskRunContext,
critical is optional, and there is no index signature for extra fields.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

---------

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* feat(core): configurable version, help menu links, and an About page (#1609)

* feat(core): add configurable version, help menu links, and an About page

- opensearchDashboards.branding.applicationVersion overrides the version
  shown in the About page and the persistent help-menu badge; falls back
  to the real build version.
- opensearchDashboards.branding.helpMenuLinks overrides the help menu's
  Documentation/Slack/GitHub/Google Group list (replaces it entirely when
  set); each entry supports an optional darkModeIcon.
- New src/plugins/about core plugin hosts the About page (moved out of
  wazuh-dashboard-plugins), with its own about.communityLinks setting
  (same {label, link, icon, darkModeIcon} shape, hides the Community
  panel when set to an empty list), registered under the same "Dashboard
  management" category/position the page had before the move.
- Synced the legacy Joi config schema (src/legacy/server/config/schema.js)
  with the new branding.* keys to fix a boot-time validation error.
- Registered the new "about" i18n namespace in src/.i18nrc.json.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): use the Wazuh copyright header on new about plugin files

The new files added for the about plugin and help_menu type used the
"Copyright OpenSearch Contributors" header template, reserved for
OpenSearch-authored files. These are wholly new, Wazuh-original files, so
per this fork's own convention (.eslintrc.js OSD_WAZUH header, "For new
files created by Wazuh Contributors") they should use "Copyright Wazuh"
instead.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs(changelog): add entries for the about plugin and branding settings

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): hide all help menu links when helpMenuLinks is empty

Treat opensearchDashboards.branding.helpMenuLinks as configured whenever it
is set, so an empty list renders no links instead of falling back to the
built-in ones, matching about.communityLinks and the documented behavior.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): register the About app in the all nav group

Add the About app to DEFAULT_NAV_GROUPS.all under the Dashboard
management category so it stays visible once the new navigation is
enabled. Previously it reached the nav group through the main plugin's
registerWazuhNavLinks, which no longer lists it after the move.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* fix(core): set the About page breadcrumb and document title

The About app never set its breadcrumb or document title, so the header
kept showing the previous app's breadcrumb (e.g. "Overview") and the tab
title stayed "Wazuh". Set both to "About" when the app mounts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Merge 4.14.10 into 5.0.0 (#1616)

Merge 4.14.9 into 4.14.10 (#1615)

* Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------




* Merge 4.14.8 into 4.14.9 (#1614)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

* Bump 4.14.8 branch (#1612)

feat: bump 4.14.8

---------




---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Resolve dashboard credentials at install and start (#1613)

* feat(packages): resolve dashboard credentials at install and start

Replace the hardcoded kibanaserver keystore pair and the plaintext
wazuh-wui password with the shared resolve-credentials script, run from
postinst/%post and from the unit's ExecStartPre=+. The script is
downloaded and checksum-verified at build time. Purge removes /etc/wazuh
only when no other Wazuh central component remains.

Closes #1594

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): ship the credentials resolver in the repo

Replace the build-time download of resolve-credentials with a script
maintained in this repository, adapted from the manager's resolver.
Only the shared wazuh-credentials.sh library is still downloaded at
build time, from wazuh-installation-assistant, into lib/.

The resolver takes --install, --upgrade, --prestart and --clear. The
maintainer scripts, the systemd unit and the SysV init script call it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): honour credentials set in the dashboard config

Treat opensearch.password and wazuh_core.hosts.default.password set in
opensearch_dashboards.yml as resolved, so the resolver neither refuses
the start nor writes keystore entries that would override the yml.
Never write opensearch.username over a user set in the yml, and skip
the wazuh-wui entry when the yml defines no default host.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): generate the AI assistant key in the resolver

Move the wazuh_ai_assistant.encryptionKey generation out of postinst
and %post into resolve-credentials. It is generated on --install and
--prestart when neither the keystore nor opensearch_dashboards.yml has
it, never on --upgrade, and never replaced. A generation failure only
warns. --clear now removes it too, so an image does not share one key
across containers.

The resolver already creates the keystore, so the maintainer scripts no
longer do.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): pick the credentials library ref from the build

Try an ordered list of wazuh-installation-assistant refs (override, tag
being built, branch being built, version branch, version tag) instead of
a single ref. A tag build only tries its tag.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): supply credentials before starting the service in CI

The unit now runs resolve-credentials --prestart, which refuses to start
while the kibanaserver and wazuh-wui passwords are unresolved. The DEB
install test started the service on a clean install with no credentials,
so the start failed.

Assert the refusal first, then write test credentials to
/etc/wazuh/credentials.env and start the service. Dump the unit journal
on failure.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): issue the dashboard TLS certificates from the shared CA

On a fresh install, resolve-credentials now issues dashboard.pem and
dashboard-key.pem, and installs root-ca.pem, into
/etc/wazuh-dashboard/certs from the shared Wazuh root CA (/etc/wazuh/ca).
The CA is created through the shared credentials library when no
component has created it yet, and reused otherwise.

An existing complete pair is kept, a partial pair is refused, and an
anchor-only CA cannot issue, so the operator is told to stage a pair.
--upgrade and --prestart never touch the certificates; --clear removes
them together with a CA minted on this host. Files are staged in a
root-only directory and published with ln -T, and each step is logged
with public data only.

The packages now depend on openssl (and diffutils and util-linux on
RPM), which the issuance and the shared library need.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs(packages): reference the manager's certificate issuance

Point the dashboard certificate step and its README to the manager's
issue and PR it mirrors: wazuh/wazuh#39554 and wazuh/wazuh#39571.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* revert: reference the manager's certificate issuance

This reverts commit e9bde535c6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): supply credentials before starting the service in RPM CI

The unit runs resolve-credentials --prestart, which refuses to start while
the kibanaserver and wazuh-wui passwords are unresolved. The RPM install
test still started the service on a clean install with no credentials, so
the start failed (run 36148424354).

Move the inline SSH test into rpm-test-install-uninstall.sh, mirroring the
DEB test: check the issued certificates, assert the refusal, write test
credentials to /etc/wazuh/credentials.env, start the service and dump the
unit journal on failure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): only reject passwords the keystore would not store verbatim

resolve-credentials validated the consumed kibanaserver and wazuh-wui
passwords against the shared password policy. That policy is fetched
unpinned from wazuh-installation-assistant and has since gained a symbol
requirement, so the CI test passwords were rejected and the service did
not start (run 36389268794). The dashboard's own message already
described an older version of the rule.

The indexer and the manager own these passwords and enforce the policy.
The dashboard now checks only what is its own concern: keystore add
trims the value and stores it JSON.parse'd, so reject any value it would
not store verbatim (JSON numbers, booleans, quoted strings, arrays,
objects, surrounding whitespace). The check repeats add.js with the
bundled Node.

Add a negative case to the DEB and RPM install tests asserting that a
JSON number is reported as INVALID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): add a VM test matrix for install and start

vm-test-matrix.sh runs 21 cases against a built .deb or .rpm on a
disposable VM: fresh install, credentials from credentials.env, the
environment and the yml, invalid values, a refused credentials file,
shared CA reuse, anchor-only CA, operator and partial certificate pairs,
custom SANs, --clear, removal, reinstall and, with --previous, upgrades.
The host is wiped after every case and a summary is printed.
--clean-only wipes the host without running a case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): cover install orders with the manager and indexer

Rename --package and --previous to --dashboard and --dashboard-previous,
and add --manager and --indexer. Dashboard-only cases are now D01-D21;
the new F01-F08 cases need both sibling packages and run only when they
are given.

F01-F06 install the indexer, the manager and the dashboard in every
order and check after each step that the dashboard resolves exactly
what credentials.env holds, names what it lacks, refuses to start until
both keys are resolved, and reuses or mints the shared CA. F07 purges
the dashboard with the siblings still installed; F08 reinstalls it. The
siblings' own start and CA are recorded as [INFO].

Cleanup purges wazuh-manager and wazuh-indexer too when their packages
are given, or with --force.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): let the service group read the shared credentials library

At startup OSD's i18n loader globs */.i18nrc.json under the installation
root, which lists every top-level directory. lib/ was root:root 0750, so
the wazuh-dashboard user got EACCES on scandir and the server exited with
a fatal error.

Keep lib/ and wazuh-credentials.sh owned by root, so the service user
still cannot modify what ExecStartPre=+ sources as root, but give them
the wazuh-dashboard group (0750 / 0640) so the loader can list the
directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): read the keystore before grepping it in CI

`keystore list | grep -q` under `pipefail` failed when grep closed the
pipe on the first match and the keystore CLI hit EPIPE, reporting the AI
assistant key as missing although it was present (RPM aarch64).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Check Prettier only on the lines a change writes (#1608)

* fix(ci): check Prettier only on the lines a change writes

The check runs over every file a change touches. Most of this repository
comes from OpenSearch Dashboards, which never ran Prettier over its own
tree, so changing two lines in a file that was never formatted demands a
reformat of the whole file. On wazuh/wazuh-dashboard-alerting#148 that was
318 lines of rewriting to land 400 lines of work.

No configuration fixes this. Sweeping nine Prettier versions from 1.19.1 to
3.6.2 and every single-option change against upstream's own `.prettierrc`
leaves a floor of 73 of 670 source files failing. There is nothing to align
to.

Rewriting those files is what costs us. Each one diverges from its
counterpart on the other version branches, so the next upward merge or
cherry-pick conflicts, and the next OpenSearch migration replays a larger
Wazuh delta onto the new upstream tree.

So a change answers for the lines it writes and nothing else. A file it adds
is checked in full; a line it did not touch is not checked.

`scripts/prettier-check-changed.js` compares what the change wrote against
what Prettier wants and reports the overlap. `--fix` corrects those lines
and leaves the rest of the file alone. A merge branch passes the branch
being merged as a second base, so lines that exist in either parent are not
the merge's own. The pre-commit hook returns early during a merge,
cherry-pick, revert or rebase, where it was blocking
`git cherry-pick --continue` during the scheduled merges.

Backtested over 43 merged pull requests across the six repositories it
spares 28 of 29 files, with no false positives.

Refs wazuh/wazuh-dashboard#1605

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(ci): compare against the merge base and follow renames

Three problems found in review.

The check diffed against the tip of the base branch. When the base moves
ahead after a pull request branches off, that diff also reports the base's
own later commits, in reverse, and blames them on the change. A pull request
that adds one line was asked to reformat a line the base had already fixed.
Resolve each base with `git merge-base <ref> HEAD` instead, which is what
GitHub uses for "Files changed", so the check and the diff a reviewer reads
agree. The workflow needs the shared history for that, so the checkout takes
`fetch-depth: 0`.

A renamed file was checked in full. Git cannot pair a rename when the diff
receives only the new path, so it reported the file as added. Pass both paths.
The rename map was also built against the first base alone, so with two bases
the second lookup missed and the file looked new again; build one map per
base. Any upward merge carrying a rename hit this.

The `--fix` hint named `scripts/`, which is wrong in `wazuh-dashboard` where
the script lives in `dev-tools/`. Derive the path from the running script.

Refs wazuh/wazuh-dashboard#1605

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Fix --clear removing a CA it did not mint, and RPM ownership of a pre-staged certificate pair (#1621)

* fix(packages): only clear a shared CA the dashboard minted

--clear removed the shared root CA whenever root-ca.key existed, which also
destroys an operator-staged signing CA. Record the mint with
.wazuh-dashboard-bootstrap-ca under the credentials lock, as the manager does
with .wazuh-manager-bootstrap-ca, and delete the CA only when that marker is
present. Also remove staging directories an interrupted issue left behind,
and refuse a non-root --clear instead of reporting a clear that did not happen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): give a pre-staged certificate pair to the service user on RPM

A pair staged into /etc/wazuh-dashboard/certs before the package is
installed (e.g. by the installation assistant) is root:root, because the
service user does not exist yet. The resolver keeps an existing pair as it
finds it, so on RPM the service failed with EACCES reading
dashboard-key.pem. DEB was unaffected: its postinst already runs chown -R
on the configuration directory before the resolver.

Chown certs/ to wazuh-dashboard in %post before the resolver, on install
and upgrade, as the indexer and the manager do in their packaging. D13 now
checks the ownership and starts the service with the staged pair.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* Stop the service user from running code as root through the packages (#1620)

* build(packages): install /usr/share/wazuh-dashboard as root:root

The deb and rpm packages installed the whole installation directory as
wazuh-dashboard:wazuh-dashboard, so the service user could replace the code
that root runs from ExecStartPre=+ (bin/resolve-credentials, lib/, node/).
The directory is now root:root, with directories and executables at 755 and
other files at 644. data/ stays wazuh-dashboard:wazuh-dashboard 750 because
the dashboard writes to it at runtime. /etc/wazuh-dashboard is unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): keep root from trusting the service user's environment

/etc/default/wazuh-dashboard was owned by the service user, but root reads
it at every start: systemd passes it to ExecStartPre=+ through
EnvironmentFile=, and the SysV script sources it. The service user could
therefore choose what resolve-credentials ran as root.

- Install /etc/default/wazuh-dashboard as root:wazuh-dashboard 0640, and
  fix its ownership on upgrade in postinst and %post.
- When run as root, resolve-credentials sets a fixed PATH and unsets
  LD_PRELOAD, LD_LIBRARY_PATH and NODE_OPTIONS.
- Read wazuh-credentials.sh only from lib/ of the installation directory:
  drop the WAZUH_SHARED_HELPER_DIR override and the copy next to the script.
  The error now names the expected path.
- Run the node call in keystore_stores_verbatim as the service user.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Make the dashboard keystore readable only by its owner (#1622)

The keystore is encrypted with an empty password, so its file mode is the
only thing keeping the secrets private. It was written with the default
mode (0644 under a 022 umask), readable by every local user once the
parent directory protection is relaxed or bypassed.

Keystore.save() now creates the file with mode 0600 and restricts an
existing file before writing to it. Every writer goes through it: the
keystore CLI, and so the credentials resolver at install and pre-start.
The deb postinst and rpm %post also enforce 0600 and wazuh-dashboard
ownership on every install, so keystores created by earlier packages are
fixed on upgrade. The package install tests check the mode.

Closes #1619

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Fix the 5.x dev Docker image workflow and make plugin branches resolvable (#1593)

* Fix the 5.x dev Docker image workflow and make plugin branches resolvable

Start the Docker daemon on the AWS CodeBuild runners instead of pruning a
daemon that is not running, which aborted every scheduled run. Reduce the
schedule to a weekly build, add a plugins_branch input that falls back per
repository to the branch the workflow runs on when the branch does not exist
there, check out the requested branch in the build job, and let the inputs
default to the versions in package.json and .nvmrc.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Authenticate against Docker Hub before building the dev image

The build failed pulling node:22.22.0 with a 429 Too Many Requests: the AWS
CodeBuild runners share an IP pool that exhausts the Docker Hub anonymous pull
limit. Log in with the credentials the other build workflows already use.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Add diagnostics to the dev image build job

The build job died after 69 minutes with the build step still in progress and
no archived logs, so the failure cannot be read. Cap the job below the runner
reclaim window so GitHub stops it and keeps the logs, print the build with
plain progress, report memory, disk and kernel OOM kills after the step, and
stop the matrix from cancelling the sibling architecture.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Fall back to main when the workflow branch is missing in a plugin repository

The existence check only ran when plugins_branch was provided, so a run from a
branch of this repository that the plugin repositories do not have cloned a
non-existent branch. Walk the candidates in order - requested branch, workflow
branch, main - and use the first one that exists in each repository.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Raise the dev image build timeout to 90 minutes

With logs archived the build proved to need ~55 minutes of layers - 36 of them
in the optimizer warmup - plus the push to Quay.io, and it reports no OOM kills
and 100G of free disk. Give the job room to finish instead of cutting it in the
middle of the push.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Stop forcing the vfs storage driver on the Docker daemon

On the arm64 runner the daemon we start is the one that serves the build, and
vfs copies the whole filesystem on every layer: WORKDIR took 97s and a 1 KB
COPY took 19 minutes, against 0.2s and 0.1s on amd64, where a pre-existing
daemon on overlay2 answered instead. Reuse the running daemon when there is
one, let dockerd pick its driver otherwise, and keep vfs only as a fallback.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Pick the Docker storage driver by probing overlay stacking

Letting dockerd choose broke the arm64 job: it picked overlayfs and then failed
to mount, because / is an overlay mount on that runner and overlay does not
stack. Probe an overlay mount first, use the default driver when it works, try
fuse-overlayfs when it does not, and keep vfs as the last resort.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Build the dev image in a single expensive layer

Runners whose root filesystem is an overlay mount cannot stack overlay and fall
back to the vfs storage driver, which copies the whole tree on every layer.
Once /home/node/kbn holds node_modules that is about 19 minutes per layer, and
the checkout was followed by six of them - two WORKDIR, three COPY and two RUN
- which is over an hour of pure copying on the arm64 runner and free on amd64.
Copy the scripts before the checkout, where the tree is still empty, and run
the bootstrap, the plugin install and the optimizer warmup in one layer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Keep the image build output as an artifact

GitHub does not archive the log of a job it cancels, and the arm64 job is
cancelled by the timeout on every run, so three runs in a row left no trace of
which storage driver was chosen or how long each layer took. Tee the build
output to a file and upload it even when the step fails.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Drop the second stage of the dev image build

The stage existed to keep the intermediate layers out of the pushed image, but
the build is a single layer now and there is nothing left to drop. All it did
was copy /home/node/kbn in full - 320s on amd64, another whole-tree copy under
vfs - and chown every file in node_modules, which the git clone had already
created as node.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Raise the build timeout to 115 minutes

The CodeBuild runners now allow 120 minutes, but the job kept being cut at 90
by the workflow's own timeout, which was the lower of the two. Leave a margin
below the runner limit so GitHub is the one that stops a build that does not
finish, and the build log is uploaded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Set the build timeout to 120 minutes

Match the limit the CodeBuild runners now allow.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

---------

Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Diego García <82405377+Ripdiegozz@users.noreply.github.com>

* Keep the service user out of root's credential resolver paths (#1623)

The resolver runs as root from the maintainer scripts and ExecStartPre=+,
while /etc/wazuh-dashboard belongs to the service user. Three paths still
let that user steer root:

- --clear deleted dashboard.pem, dashboard-key.pem and root-ca.pem through
  the absolute ${CERTS_DIR} path, so a certs/ replaced with a symlink made
  root delete those names wherever it pointed, e.g. the shared CA anchor.
  It now enters certs/ as the issuing path does, removes relative to it,
  and refuses (and fails) when certs/ is not a real directory.

- The SAN list was written and read back through $(pwd -P)/<stage>/sans,
  which is resolved again through certs/ on each use. Swapping certs/
  between the two let the service user choose the names the shared CA
  signs. It is now built inside _dc_issue_pair, relative to the verified
  root-only staging directory.

- runuser kept the keystore and Node children in root's session and
  environment: from an interactive dpkg/rpm they could open root's
  terminal (TIOCSTI) and read what root exported, credentials included.
  Every child now goes through as_service_user: setsid (-w where
  util-linux has it) and env -i with only PATH and OSD_PATH_CONF.

The VM test matrix gains D22 (--clear with a symlinked certs/) and D23
(a node.options probe run from a terminal sees no tty and no root env).

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Restrict the not-ready healthcheck API to critical tasks and hide task data (#1624)

* Restrict the not-ready healthcheck API to critical tasks and hide task data

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Hide non-critical task errors on the not-ready server and escape the page output

- Replace the error of tasks that are not enabled and critical with a generic message, because it can carry node names and certificate details.
- Sort and dedupe the requested task names so reordered or repeated names share one run.
- Escape task names and errors on the not-ready page.
- Make the route test mocks return real task results so the checks exercise stored data.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Hand the kept configuration over to root on RPM removal (#1625)

Removing the RPM package deletes the wazuh-dashboard user and group but
keeps /etc/wazuh-dashboard, whose certificates, private keys and keystore
stayed owned by the freed UID and GID. The next system account created
could inherit them and read those secrets.

Before the account goes, %postun now makes root the owner of everything
the account or its group owns in /etc/wazuh-dashboard, strips group and
other access, and reports what it kept, as the Wazuh indexer package
does. A kept /etc/default/wazuh-dashboard.rpmsave loses the group too.
A fresh install takes the directory back. The package test checks both.

Related: wazuh/wazuh-dashboard-plugins#9257

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Merge 4.14.10 into 5.0.0 (#1635)

Merge 4.14.9 into 4.14.10 (#1634)

* Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------




* Merge 4.14.8 into 4.14.9 (#1614)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

* Bump 4.14.8 branch (#1612)

feat: bump 4.14.8

---------




* Bump 4.14.9 branch (#1627)

feat: bump 4.14.9

* Change tag reference for 4.14.9 (#1629)

chore(tag-reference): change tag reference for 4.14.9

---------

Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>

* Fix Indexer management and Dashboards Management menu paths in docs (#1636)

* docs: fix Indexer management menu name on the read-only mode page

The read-only mode page named a Management menu that does not exist
in 5.0; the top-level category for indexer administration is Indexer
management (src/core/utils/default_app_categories.ts:76-82).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs: replace nonexistent Stack Management entry in Discover guide

getting_started_with_discover.md pointed to a 'Stack Management'
sidebar entry that doesn't exist in the Wazuh dashboard. The app is
titled Dashboards Management, under the Dashboard management category
(src/plugins/management/public/plugin.ts:84-86), with Data sources
(src/plugins/data_source_management/common/index.ts) as one of its
sections. Fix the same wrong label in the dsm_flow.puml diagram.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs: address review feedback on dashboard menu paths

- Rewrite the Discover data selector sub-steps as a real nested list;
  the plain a.-d. lines rendered as a lazy continuation of the S3 bullet.
- Drop the nonexistent "☰" label from the Dashboards Management path and
  note that the Wazuh dashboard hard-disables home:useNewHomePage, so the
  classic navigation always applies.
- Align the workspace "Data sources" tab casing.
- Replace the leftover "stack management" mention in user_stories.md.
- Rename the stale Page-Stack alias in dsm_flow.puml and regenerate
  dsm_flow.png from it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Fix the not-ready page false success notice (#1640)

* Show the not-ready success notice only after checks

The not ready page reported that no critical errors remain while the
health checks had not run yet, because only enabled, finished and failed
tasks counted. Show the success notice only once enabled tasks finished,
and a generic waiting notice otherwise.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Log the cause of bodyless indexer response errors

Responses without an OpenSearch error object, such as the security
plugin answering 503 or 401 with plain text, were logged as
"Response Error". Include the status code, the request method and path
and the bounded plain-text body so the cause shows in the server log.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Reword the not-ready waiting notice

The page cannot tell why the health checks have no results yet: the server may be waiting for the indexer, running saved object migrations or running the checks. State only that, and point to the logs.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Mark the Wazuh changes in the OpenSearch client

configure_client.ts and its test come from OpenSearch Dashboards. Keep the original code commented out and tag each Wazuh addition.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Fix the type of the bounded log line test

The collected log entry is typed string | Error, so reading .length broke the TypeScript project build (tsc -b tsconfig.refs.json) in the bootstrap step.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

---------

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* End the package install with how to log in (#1639)

feat(packages): end the install with how to log in

Print the dashboard URL, the admin login and the start command at the end of a fresh install. Show the certificate detail only with WAZUH_DASHBOARD_VERBOSE=1.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Bump 5.0.0 branch (#1645)

feat: bump 5.0.0

* Revert bump 5.0.0 branch (#1647)

feat: revert 5.0.0 references

* Bump 5.0.0 branch (#1650)

feat: bump 5.0.0

* Name the browser tab after the current app and add a skip link (#1643)

* fix(chrome): name the browser tab after the current app

Set the tab title to "<app title> - <applicationTitle>" on every app change instead of resetting it to the base title, so every plugin's app gets a distinct title. Fall back to Wazuh instead of OpenSearch Dashboards when applicationTitle is invalid.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* feat(rendering): add a skip to main content link

Render a skip link before the header, hidden until focused with Tab. Enter moves focus to the app wrapper without changing the URL hash, which the apps use for routing. Not rendered while the header is hidden, such as on the login page.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>

* Fix Timeline label regex blocking the server (#1652)

fix(timeline): run .label() regex with re2js to avoid ReDoS

A user-supplied .label() regex ran on native RegExp, so a nested quantifier could block the server's event loop. re2js runs in linear time and rejects backreferences and lookarounds.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Minify the production bundles (#1646)

* feat(optimizer): minify the production bundles

Enable SWC compress and mangle for the optimizer bundles, which were
shipped with both disabled since the fork from Kibana.

Keep class and function names: code reads constructor.name (error
messages, error boundaries), and Babel compiles our classes to
functions, so keep_classnames alone does not protect them.

On a local amd64 package built from the same commits as the CI one,
the entry bundles shrink 38% decoded and 26% brotli, and the deb 3.3%.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* test(optimizer): update the dist bundle snapshot

The production bundles are now compressed and mangled, so the dist
snapshot of the foo and bar fixture bundles holds the minified code.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

---------

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Disable and reload the wazuh-dashboard systemd unit on RPM and DEB removal (#1654)

* fix(packaging): disable wazuh-dashboard systemd unit on RPM removal

systemctl stop in the %preun scriptlet left the unit enabled, leaving a
dangling multi-user.target.wants symlink and a not-found unit once the
RPM deleted the unit file. Mirror the DEB prerm and the wazuh-indexer
RPM by also running systemctl --no-reload disable before removal.

Closes #1653

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packaging): mirror the indexer's stop/disable/reload sequence in the RPM and DEB packages

The RPM %preun already stops and disables the unit, but nothing told
systemd to forget it once the unit file was actually removed, so
systemctl list-units could keep reporting it as not-found until some
unrelated reload happened. The DEB prerm disabled the unit without
--no-reload, and its postrm never reloaded either. Add the matching
daemon-reload to %postun/postrm, and --no-reload to the DEB disable
call, exactly as the wazuh-indexer RPM and DEB packages already do.

Closes #1653

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packaging): add --no-reload to the RPM stop call, matching the indexer

The DEB prerm and the wazuh-indexer RPM both suppress the reload on
stop since disable (right after) reloads once anyway; the dashboard
RPM's stop call was missing that flag.

Closes #1653

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packaging): add --no-reload to the RPM's upgrade stop call too

%pre stops the running service before an in-place upgrade, same as
%preun does before removal. The wazuh-indexer RPM suppresses the
reload there too, since the unit file isn't changing yet.

Closes #1653

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Rename wazuh-wui to wazuh-internal-client (#1651)

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Configura CA validation by default (#1660)

* Merge 4.14.10 into 5.0.0 (#1671)

Merge 4.14.9 into 4.14.10 (#1664)

* Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------




* Merge 4.14.8 into 4.14.9 (#1614)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

* Bump 4.14.8 branch (#1612)

feat: bump 4.14.8

---------




* Bump 4.14.9 branch (#1627)

feat: bump 4.14.9

* Change tag reference for 4.14.9 (#1629)

chore(tag-reference): change tag reference for 4.14.9

* Bump 4.14.9 branch (#1656)

feat: bump 4.14.9

* Change tag reference for 4.14.9 (#1657)

chore(tag-reference): change tag reference for 4.14.9

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>

* Merge 4.14.11 into 5.0.0 (#1686)

Bump 4.14.11 branch (#1663)

feat: bump 4.14.11

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>

* Rework the wazuh-dashboard 5.0 package (#1678)

* Open the wazuh-dashboard 5.0 package rework integration branch

Integration branch for #1670. The sub-issue PRs target this branch.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Make /etc/wazuh-dashboard root-owned (#1674)

* Rewrite the dashboard credential resolver in Node

Replace the shell resolver and the shared lib/wazuh-credentials.sh with
resolve-credentials.js, run on the bundled Node by a short launcher. It
follows the per-package model: own CA in ca/, export/ca.pem, values from
the environment, local.env and the peers' export/ directories, and never
touches /etc/wazuh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Use the Apache-2.0 license header in the resolver launcher

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* fix(packaging): make /etc/wazuh-dashboard root-owned

Install the configuration directory as root:wazuh-dashboard so the
service reads its configuration, keystore and TLS material through its
group and can no longer rewrite them.

- DEB postinst and RPM %post stop handing the directory to the service
  account and run the ownership block from #1666 before the resolver
  (and, on DEB, before the upgrade restart), which also takes back an
  RC1 directory and accepts one staged by the operator. No step follows
  a symbolic link.
- The keystore is set to root:wazuh-dashboard 0640.
- DEB rules and RPM %files ship the directory, opensearch_dashboards.yml
  and node.options as root:wazuh-dashboard.
- The VM test matrix asserts the new layout on fresh install, operator
  staging and upgrade.

Refs: #1666
Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* chore(packaging): trim config ownership comments

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* test(packaging): drop the root-ca.pem check from the upgrade case

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

---------

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>
Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Bind port 443 through a systemd ambient capability instead of setcap (#1675)

* fix(packages): bind port 443 through a systemd ambient capability

Grant CAP_NET_BIND_SERVICE from the unit instead of setcap on the bundled node binary, and drop the libcap2-bin and libcap dependencies.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(packages): reload the unit on upgrade and check the 443 bind in CI

Run daemon-reload on every DEB configure and in RPM %posttrans, so a stopped or restarted service starts with the new unit. CI package tests now wait for the 443 listener and check the unit-granted capabilities; the VM matrix also asserts CapAmb and CapBnd.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Ian…
* Adapt RPM smoke-test workflow to Allocator package layout

wazuh-automation refactored the Allocator into an installable Python
package (wazuh-automation#3656). Update the wazuh-automation clone,
install, and invocation commands in the RPM smoke-test job to match
the new src/ layout and package interface.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Commit to test

* Pin Allocator install/invocation to Python 3.12

The Allocator package declares requires-python = ">=3.12,<3.13", but
the CodeBuild runner's default python3 is 3.10. Under 3.10 the pip
install silently produced a broken UNKNOWN-0.0.0 wheel with no
allocation module, causing ModuleNotFoundError at invocation. Install
and invoke via python3.12 explicitly (already available through the
deadsnakes PPA on the runner) instead of the system default python3.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Revert commit to test

* Fix python3.12 detection on runners with pyenv in RPM smoke test

Runners with pyenv expose an inactive python3.12 shim, so 'command -v'
succeeded but invoking it failed. Check that python3.12 actually runs,
activate pyenv's 3.12 via PYENV_VERSION (persisted in GITHUB_ENV) or
install it via apt. Skip Allocator teardown when no machine was created.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Report skipped bumps in the repository bumper workflow (#1492)

Improve repository bumper error handling

* Recalculate flyout position when the sidecar is opened (#1503)

* Adapt flyout position in relation to the sidecar

* Add changelog

* Change resizable button emphasis style from :focus to :active (#1508)

* fix(sidecar): change resizable button emphasis style from :focus to :active

Update the .sidecar-resizableButton CSS to emphasize the "grab" icon
on :active instead of :focus, matching the intended interaction
feedback when dragging the resizer.

Closes https://github.com/wazuh/wazuh-dashboard-plugins/issues/8989

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): remove leftover native focus outline on resizable button

The resizable button programmatically calls .focus() on every click,
so after removing the custom :focus emphasis in favor of :active, the
browser's default focus outline was left showing as an unstyled
colored border until focus moved elsewhere. Suppress it for
mouse/touch interaction while keeping it for keyboard users via
:focus-visible.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(sidecar): opt out resizable button from the global focus-ring animation

The resizable button programmatically calls .focus() on every click,
which triggered OSD's global brute-force focus-ring animation
(:focus:not([class^="eui"]):not(.osd-resetFocusState) in _base.scss)
since the button isn't an EUI component. That showed as a lingering
colored border after dragging, independent from the button's own
:active styling. Opt out via the "osd-resetFocusState" class, which is
the mechanism _base.scss already documents for components with
hand-crafted focus states, instead of fighting the rule's
!important/specificity locally. Supersedes the previous outline:none
attempt, which didn't target the actual animation.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(sidecar): allow configuring the resizable button className

Add an optional className prop to ResizableButton, and forward it from
a new classNameButton option on OverlaySidecarOpenOptions/Sidecar, so
callers of overlays.sidecar.open() can style/opt-out the resizer
button (e.g. pass "osd-resetFocusState" to drop the global focus-ring
animation) without hardcoding it in the component.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Change top bar health-check icon (#1505)

* feat: update health check indicator

* Change top bar health-check icon to a pulse shown only when attention is needed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(core): use kebab-case for sidecar docked-mode CSS variable

Rename --osdSidecarSize to --osd-sidecar-size and switch attribute
selectors to double quotes to satisfy the repo's stylelint rules
(custom-property-pattern, string-quotes), registering sidecar.scss
in the global selectors allowlist for its .euiFlyout references.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* chore: use constant

* Rework health-check popover

* Rework health-check popover

* List failing health checks in the nav-button popover

Show the enabled non-green checks as an EuiHealth list in the health-check
popover, labelled by the check name and with the error surfaced in a tooltip.
Use the shared mapTaskStatusToHealthColor helper and TASK.RUN_RESULT constants
instead of magic strings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Fix popover closes when clicking inside

* Close popover after navigating to the health check

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Bump 5.0.0 branch (#1513)

feat: bump 5.0.0

* Fix RPM changelog entry order causing build failure (#1516)

Fix RPM changelog entry order for 5.0.0

The 5.0.0 changelog entry was placed out of descending chronological
order, causing rpmbuild to fail while parsing %changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1517)

Remove unnecessary debhelper install-time dependency (#1484)

fix: remove unnecessary debhelper install-time dependency

debhelper is only required to build the .deb package (declared under
Build-Depends in dev-tools/build-packages/deb/debian/control), not to
install a pre-built one. Remove it from the apt-get install steps used
to test package install/upgrade.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1537)

Merge 4.14.9 into 5.0.0: no changes (verified 2026-08-28)

* fix: remove inert opensearch_security.cookie.ttl setting (#1534)

The dashboard config declares opensearch_security.cookie.ttl, but the
security plugin never reads it: only opensearch_security.session.ttl
governs session/cookie expiry. Shipping the setting misleads operators
into believing it bounds the cookie lifetime.

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Bump 5.0.0 branch (#1545)

feat: bump 5.0.0

* Revert bump 5.0.0 branch (#1546)

feat: revert 5.0.0 references

* Fix changelog not in descending chronological order (#1548)

* fix: keep RPM changelog entries in descending date order on re-bump (#1549)

Re-bumping an existing version updated its date in place instead of
repositioning it, so a newer date could end up below older entries and
rpmbuild rejected the spec (%changelog not in descending chronological
order). The entry is now removed and reinserted at the position
matching its date.

Also fixes date/sed portability on macOS (BSD date/sed vs GNU), and
makes an invalid date abort the script instead of writing the error
text into the changelog.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Bump 5.0.0 branch (#1551)

feat: bump 5.0.0

* Review the 5.0.0 changelog (#1556)

* docs(changelog): review the 5.0.0 entries

Removed the open redirect fix entry (#1285) and the pre install script
check entry (#1328, #1365).

Reordered the sections to Added, Changed, Removed, Fixed, and qualified
the two wazuh-dashboard-plugins references so they no longer read as
wazuh-dashboard issues.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): reference issues instead of pull requests

Each entry now links the issue the pull request closed, so the reference
carries the description and the discussion instead of just the diff.

Where an entry listed several references that resolve the same issue, it
collapses to that one; where they resolve different issues, the entry
keeps the main one and the rest are attached to it as sub-issues on
GitHub, following the shape of wazuh-dashboard-plugins#8789.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(changelog): merge the health check service and app entries

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* docs(changelog): point the health check entry at its parent issue

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Merge 4.14.9 into 5.0.0 (#1563)

Merge 4.14.8 into 4.14.9 (#1562)

Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x
# Conflicts:
#	dev-tools/build-dev-image/README.md
#	dev-tools/build-dev-image/build-multiarch.sh
#	dev-tools/build-dev-image/install-plugins.sh
#	dev-tools/build-dev-image/plugins
#	dev-tools/build-dev-image/warmup-opensearch_dashboards.yml
#	dev-tools/build-dev-image/warmup-optimizer.sh
#	dev-tools/build-dev-image/wzd.dockerfile

* Bump 5.0.0 branch (#1567)

feat: bump 5.0.0

* Bump 5.0.0 branch (#1571)

feat: bump 5.0.0

* Fix empty error message in dashboard save failure toast (#1573)

The danger toast shown when saving a dashboard fails interpolated
savedDashboard.message, a property that does not exist on the saved
object instance, so the message always rendered as
"Dashboard 'X' was not saved. Error:" with nothing after "Error:".

Use the caught error's message instead.

Closes #1568

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Show the root cause of the failure in the error toast full error modal (#1574)

The See the full error modal built its copyable block from caused_by, which
can hold a failure raised while the response itself was being built rather
than the failure that made the request fail: querying a field that is not
searchable reported a null_pointer_exception about reducePhase.aggregations
instead of the query_shard_exception the backend reports under root_cause.

The reason of the root cause is now shown inside the danger callout, under
the message of the error, and is stripped of URLs, IP addresses and
filesystem paths. The copyable block keeps the content it had on 5.0.0,
the client stack trace included.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Merge 4.14.9 into 5.0.0 (#1581)

Merge 4.14.8 into 4.14.9 (#1580)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Reorder rpm changelog

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>

* Merge 4.14.10 into 5.0.0 (#1602)

* Bump 4.14.10 branch (#1589)

feat: bump 4.14.10

* Merge 4.14.9 into 4.14.10 (#1601)

Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Let a health check task report red, and show that red in the overall status (#1595)

* feat: Add TaskResult so health check tasks report their own result status

A health check task could only resolve or throw, and the registration-time
`critical` flag decided whether a throw became yellow or red. Because that same
flag also decides whether a failure blocks startup, a task had no way to report
red without holding the dashboard behind the "server is not ready yet" screen.

A task may now resolve a branded `TaskResult` and pick its own result status.
`critical` is untouched and goes on deciding whether a red result blocks
startup, so the new reachable combination is a non-critical red: visible,
without blocking.

The result is branded with a registry symbol rather than detected structurally.
An existing task already resolves `{ status: 'ok' }` as its data, so a
structural guard would reinterpret plain task data as a status and drop the
payload.

Tasks that resolve or throw are unaffected. No existing task changes.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* fix: Respect the check own result when computing the health check overall status

computeOverallStatus decided the overall status only from the critical flag,
so a check reporting red landed on the header as yellow. Every check registered
by the Wazuh plugins is non critical, which capped the indicator at yellow and
made red unreachable.

The aggregation now returns red for any finished check whose result is red,
keeps escalating a non green critical check to red, and returns yellow for any
other non green result.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* fix: Type the health check task error property as string or null

`public error = null` made TypeScript infer the literal type `null`, so
assigning a TaskResult message broke `tsc -b tsconfig.refs.json` and the CI
bootstrap. The catch branch got away with the same assignment because a catch
binding is `any`.

`ITask['error']` is already `string | null`, which is what the property held
all along.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* docs: Drop the redundant health check changelog entry

The overall status aggregation was not fixing a defect users could reach. In
5.0.0 the only assignment of a red result sits behind `if (this.critical)`, so
a non-critical red does not exist and the old aggregation was equivalent to the
new one. That state is created by this branch, so the behaviour belongs to the
Added entry rather than to a separate Fixed one.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* change: Require health check tasks to return a task result

A task could resolve any value, which the platform stored as data and marked
green, or resolve a branded TaskResult. Two return shapes for one outcome, and
the plain one gave a task no way to say anything but green.

`TaskDefinition.run` now returns a TaskResult. A value that is not branded is
rejected at runtime as well, because the type does not reach a task written in
JavaScript, and a silent gray result would be worse than a loud failure.

Throwing is unchanged and stays the path for the unexpected.

BREAKING CHANGE: every registered task must return taskResult.ok, warning or
error. The tasks in wazuh-dashboard-plugins migrate alongside this.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* docs: Update the health check README for the task result contract

The README documented the semantics this branch inverts. It stated in six
places that the result color encodes criticality: red meant a critical failure
and yellow a non-critical one, and the summary went red only for a critical
task. That held while the only path to red was a throw from a critical task.

It also described the summary with the startup blocking rule. Those are two
aggregations answering different questions, and only one of them changed, so
they are now documented apart.

The registration example returned nothing, which the new contract rejects.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Break word to prevent overflow

* change: Provide the result constructors in the health check task context

A task had to build its TaskResult itself, and core exported no constructor to
build one with. wazuh-dashboard-plugins answered that by hand-rolling a mirror
of the contract, relying on Symbol.for to resolve to the same brand. A required
contract nobody can import is a contract everybody copies.

The context a task already receives now carries the constructors, so a task
reports a result without importing anything. TaskRunContext replaces the `any`
the run parameter used to be, and the contract types are exported by name,
closing the TODO that kept them private.

Suggested by @Desvelao in review.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* refactor: Remove the unused health check ITask from the common types

It declared `run` as returning a generic `Promise<Result>`, which contradicts
both the task contract and the `ITask` the server defines. Nothing imported it,
in this repo or in wazuh-dashboard-plugins.

The name still exists in the server task types, which is the one implemented.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* change: Export the health check task contract from the server entry point

A plugin registering a check could not import TaskDefinition, TaskRunContext,
TaskResult or TaskResultFactory from src/core/server, so it redeclared them.
They are exported there now.

The manager annotates the context it passes, so the compiler checks that the
injected constructors reach the task.

The README interface block now matches the type: run receives a TaskRunContext,
critical is optional, and there is no index signature for extra fields.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

---------

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* feat(core): configurable version, help menu links, and an About page (#1609)

* feat(core): add configurable version, help menu links, and an About page

- opensearchDashboards.branding.applicationVersion overrides the version
  shown in the About page and the persistent help-menu badge; falls back
  to the real build version.
- opensearchDashboards.branding.helpMenuLinks overrides the help menu's
  Documentation/Slack/GitHub/Google Group list (replaces it entirely when
  set); each entry supports an optional darkModeIcon.
- New src/plugins/about core plugin hosts the About page (moved out of
  wazuh-dashboard-plugins), with its own about.communityLinks setting
  (same {label, link, icon, darkModeIcon} shape, hides the Community
  panel when set to an empty list), registered under the same "Dashboard
  management" category/position the page had before the move.
- Synced the legacy Joi config schema (src/legacy/server/config/schema.js)
  with the new branding.* keys to fix a boot-time validation error.
- Registered the new "about" i18n namespace in src/.i18nrc.json.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): use the Wazuh copyright header on new about plugin files

The new files added for the about plugin and help_menu type used the
"Copyright OpenSearch Contributors" header template, reserved for
OpenSearch-authored files. These are wholly new, Wazuh-original files, so
per this fork's own convention (.eslintrc.js OSD_WAZUH header, "For new
files created by Wazuh Contributors") they should use "Copyright Wazuh"
instead.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs(changelog): add entries for the about plugin and branding settings

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): hide all help menu links when helpMenuLinks is empty

Treat opensearchDashboards.branding.helpMenuLinks as configured whenever it
is set, so an empty list renders no links instead of falling back to the
built-in ones, matching about.communityLinks and the documented behavior.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(core): register the About app in the all nav group

Add the About app to DEFAULT_NAV_GROUPS.all under the Dashboard
management category so it stays visible once the new navigation is
enabled. Previously it reached the nav group through the main plugin's
registerWazuhNavLinks, which no longer lists it after the move.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* fix(core): set the About page breadcrumb and document title

The About app never set its breadcrumb or document title, so the header
kept showing the previous app's breadcrumb (e.g. "Overview") and the tab
title stayed "Wazuh". Set both to "About" when the app mounts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Merge 4.14.10 into 5.0.0 (#1616)

Merge 4.14.9 into 4.14.10 (#1615)

* Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------




* Merge 4.14.8 into 4.14.9 (#1614)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

* Bump 4.14.8 branch (#1612)

feat: bump 4.14.8

---------




---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Resolve dashboard credentials at install and start (#1613)

* feat(packages): resolve dashboard credentials at install and start

Replace the hardcoded kibanaserver keystore pair and the plaintext
wazuh-wui password with the shared resolve-credentials script, run from
postinst/%post and from the unit's ExecStartPre=+. The script is
downloaded and checksum-verified at build time. Purge removes /etc/wazuh
only when no other Wazuh central component remains.

Closes #1594

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): ship the credentials resolver in the repo

Replace the build-time download of resolve-credentials with a script
maintained in this repository, adapted from the manager's resolver.
Only the shared wazuh-credentials.sh library is still downloaded at
build time, from wazuh-installation-assistant, into lib/.

The resolver takes --install, --upgrade, --prestart and --clear. The
maintainer scripts, the systemd unit and the SysV init script call it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): honour credentials set in the dashboard config

Treat opensearch.password and wazuh_core.hosts.default.password set in
opensearch_dashboards.yml as resolved, so the resolver neither refuses
the start nor writes keystore entries that would override the yml.
Never write opensearch.username over a user set in the yml, and skip
the wazuh-wui entry when the yml defines no default host.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): generate the AI assistant key in the resolver

Move the wazuh_ai_assistant.encryptionKey generation out of postinst
and %post into resolve-credentials. It is generated on --install and
--prestart when neither the keystore nor opensearch_dashboards.yml has
it, never on --upgrade, and never replaced. A generation failure only
warns. --clear now removes it too, so an image does not share one key
across containers.

The resolver already creates the keystore, so the maintainer scripts no
longer do.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): pick the credentials library ref from the build

Try an ordered list of wazuh-installation-assistant refs (override, tag
being built, branch being built, version branch, version tag) instead of
a single ref. A tag build only tries its tag.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): supply credentials before starting the service in CI

The unit now runs resolve-credentials --prestart, which refuses to start
while the kibanaserver and wazuh-wui passwords are unresolved. The DEB
install test started the service on a clean install with no credentials,
so the start failed.

Assert the refusal first, then write test credentials to
/etc/wazuh/credentials.env and start the service. Dump the unit journal
on failure.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* feat(packages): issue the dashboard TLS certificates from the shared CA

On a fresh install, resolve-credentials now issues dashboard.pem and
dashboard-key.pem, and installs root-ca.pem, into
/etc/wazuh-dashboard/certs from the shared Wazuh root CA (/etc/wazuh/ca).
The CA is created through the shared credentials library when no
component has created it yet, and reused otherwise.

An existing complete pair is kept, a partial pair is refused, and an
anchor-only CA cannot issue, so the operator is told to stage a pair.
--upgrade and --prestart never touch the certificates; --clear removes
them together with a CA minted on this host. Files are staged in a
root-only directory and published with ln -T, and each step is logged
with public data only.

The packages now depend on openssl (and diffutils and util-linux on
RPM), which the issuance and the shared library need.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs(packages): reference the manager's certificate issuance

Point the dashboard certificate step and its README to the manager's
issue and PR it mirrors: wazuh/wazuh#39554 and wazuh/wazuh#39571.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* revert: reference the manager's certificate issuance

This reverts commit e9bde535c6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): supply credentials before starting the service in RPM CI

The unit runs resolve-credentials --prestart, which refuses to start while
the kibanaserver and wazuh-wui passwords are unresolved. The RPM install
test still started the service on a clean install with no credentials, so
the start failed (run 36148424354).

Move the inline SSH test into rpm-test-install-uninstall.sh, mirroring the
DEB test: check the issued certificates, assert the refusal, write test
credentials to /etc/wazuh/credentials.env, start the service and dump the
unit journal on failure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): only reject passwords the keystore would not store verbatim

resolve-credentials validated the consumed kibanaserver and wazuh-wui
passwords against the shared password policy. That policy is fetched
unpinned from wazuh-installation-assistant and has since gained a symbol
requirement, so the CI test passwords were rejected and the service did
not start (run 36389268794). The dashboard's own message already
described an older version of the rule.

The indexer and the manager own these passwords and enforce the policy.
The dashboard now checks only what is its own concern: keystore add
trims the value and stores it JSON.parse'd, so reject any value it would
not store verbatim (JSON numbers, booleans, quoted strings, arrays,
objects, surrounding whitespace). The check repeats add.js with the
bundled Node.

Add a negative case to the DEB and RPM install tests asserting that a
JSON number is reported as INVALID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): add a VM test matrix for install and start

vm-test-matrix.sh runs 21 cases against a built .deb or .rpm on a
disposable VM: fresh install, credentials from credentials.env, the
environment and the yml, invalid values, a refused credentials file,
shared CA reuse, anchor-only CA, operator and partial certificate pairs,
custom SANs, --clear, removal, reinstall and, with --previous, upgrades.
The host is wiped after every case and a summary is printed.
--clean-only wipes the host without running a case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): cover install orders with the manager and indexer

Rename --package and --previous to --dashboard and --dashboard-previous,
and add --manager and --indexer. Dashboard-only cases are now D01-D21;
the new F01-F08 cases need both sibling packages and run only when they
are given.

F01-F06 install the indexer, the manager and the dashboard in every
order and check after each step that the dashboard resolves exactly
what credentials.env holds, names what it lacks, refuses to start until
both keys are resolved, and reuses or mints the shared CA. F07 purges
the dashboard with the siblings still installed; F08 reinstalls it. The
siblings' own start and CA are recorded as [INFO].

Cleanup purges wazuh-manager and wazuh-indexer too when their packages
are given, or with --force.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): let the service group read the shared credentials library

At startup OSD's i18n loader globs */.i18nrc.json under the installation
root, which lists every top-level directory. lib/ was root:root 0750, so
the wazuh-dashboard user got EACCES on scandir and the server exited with
a fatal error.

Keep lib/ and wazuh-credentials.sh owned by root, so the service user
still cannot modify what ExecStartPre=+ sources as root, but give them
the wazuh-dashboard group (0750 / 0640) so the loader can list the
directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* test(packages): read the keystore before grepping it in CI

`keystore list | grep -q` under `pipefail` failed when grep closed the
pipe on the first match and the keystore CLI hit EPIPE, reporting the AI
assistant key as missing although it was present (RPM aarch64).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Check Prettier only on the lines a change writes (#1608)

* fix(ci): check Prettier only on the lines a change writes

The check runs over every file a change touches. Most of this repository
comes from OpenSearch Dashboards, which never ran Prettier over its own
tree, so changing two lines in a file that was never formatted demands a
reformat of the whole file. On wazuh/wazuh-dashboard-alerting#148 that was
318 lines of rewriting to land 400 lines of work.

No configuration fixes this. Sweeping nine Prettier versions from 1.19.1 to
3.6.2 and every single-option change against upstream's own `.prettierrc`
leaves a floor of 73 of 670 source files failing. There is nothing to align
to.

Rewriting those files is what costs us. Each one diverges from its
counterpart on the other version branches, so the next upward merge or
cherry-pick conflicts, and the next OpenSearch migration replays a larger
Wazuh delta onto the new upstream tree.

So a change answers for the lines it writes and nothing else. A file it adds
is checked in full; a line it did not touch is not checked.

`scripts/prettier-check-changed.js` compares what the change wrote against
what Prettier wants and reports the overlap. `--fix` corrects those lines
and leaves the rest of the file alone. A merge branch passes the branch
being merged as a second base, so lines that exist in either parent are not
the merge's own. The pre-commit hook returns early during a merge,
cherry-pick, revert or rebase, where it was blocking
`git cherry-pick --continue` during the scheduled merges.

Backtested over 43 merged pull requests across the six repositories it
spares 28 of 29 files, with no false positives.

Refs wazuh/wazuh-dashboard#1605

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(ci): compare against the merge base and follow renames

Three problems found in review.

The check diffed against the tip of the base branch. When the base moves
ahead after a pull request branches off, that diff also reports the base's
own later commits, in reverse, and blames them on the change. A pull request
that adds one line was asked to reformat a line the base had already fixed.
Resolve each base with `git merge-base <ref> HEAD` instead, which is what
GitHub uses for "Files changed", so the check and the diff a reviewer reads
agree. The workflow needs the shared history for that, so the checkout takes
`fetch-depth: 0`.

A renamed file was checked in full. Git cannot pair a rename when the diff
receives only the new path, so it reported the file as added. Pass both paths.
The rename map was also built against the first base alone, so with two bases
the second lookup missed and the file looked new again; build one map per
base. Any upward merge carrying a rename hit this.

The `--fix` hint named `scripts/`, which is wrong in `wazuh-dashboard` where
the script lives in `dev-tools/`. Derive the path from the running script.

Refs wazuh/wazuh-dashboard#1605

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Fix --clear removing a CA it did not mint, and RPM ownership of a pre-staged certificate pair (#1621)

* fix(packages): only clear a shared CA the dashboard minted

--clear removed the shared root CA whenever root-ca.key existed, which also
destroys an operator-staged signing CA. Record the mint with
.wazuh-dashboard-bootstrap-ca under the credentials lock, as the manager does
with .wazuh-manager-bootstrap-ca, and delete the CA only when that marker is
present. Also remove staging directories an interrupted issue left behind,
and refuse a non-root --clear instead of reporting a clear that did not happen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): give a pre-staged certificate pair to the service user on RPM

A pair staged into /etc/wazuh-dashboard/certs before the package is
installed (e.g. by the installation assistant) is root:root, because the
service user does not exist yet. The resolver keeps an existing pair as it
finds it, so on RPM the service failed with EACCES reading
dashboard-key.pem. DEB was unaffected: its postinst already runs chown -R
on the configuration directory before the resolver.

Chown certs/ to wazuh-dashboard in %post before the resolver, on install
and upgrade, as the indexer and the manager do in their packaging. D13 now
checks the ownership and starts the service with the staged pair.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* Stop the service user from running code as root through the packages (#1620)

* build(packages): install /usr/share/wazuh-dashboard as root:root

The deb and rpm packages installed the whole installation directory as
wazuh-dashboard:wazuh-dashboard, so the service user could replace the code
that root runs from ExecStartPre=+ (bin/resolve-credentials, lib/, node/).
The directory is now root:root, with directories and executables at 755 and
other files at 644. data/ stays wazuh-dashboard:wazuh-dashboard 750 because
the dashboard writes to it at runtime. /etc/wazuh-dashboard is unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packages): keep root from trusting the service user's environment

/etc/default/wazuh-dashboard was owned by the service user, but root reads
it at every start: systemd passes it to ExecStartPre=+ through
EnvironmentFile=, and the SysV script sources it. The service user could
therefore choose what resolve-credentials ran as root.

- Install /etc/default/wazuh-dashboard as root:wazuh-dashboard 0640, and
  fix its ownership on upgrade in postinst and %post.
- When run as root, resolve-credentials sets a fixed PATH and unsets
  LD_PRELOAD, LD_LIBRARY_PATH and NODE_OPTIONS.
- Read wazuh-credentials.sh only from lib/ of the installation directory:
  drop the WAZUH_SHARED_HELPER_DIR override and the copy next to the script.
  The error now names the expected path.
- Run the node call in keystore_stores_verbatim as the service user.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude <noreply@anthropic.com>

* Make the dashboard keystore readable only by its owner (#1622)

The keystore is encrypted with an empty password, so its file mode is the
only thing keeping the secrets private. It was written with the default
mode (0644 under a 022 umask), readable by every local user once the
parent directory protection is relaxed or bypassed.

Keystore.save() now creates the file with mode 0600 and restricts an
existing file before writing to it. Every writer goes through it: the
keystore CLI, and so the credentials resolver at install and pre-start.
The deb postinst and rpm %post also enforce 0600 and wazuh-dashboard
ownership on every install, so keystores created by earlier packages are
fixed on upgrade. The package install tests check the mode.

Closes #1619

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Fix the 5.x dev Docker image workflow and make plugin branches resolvable (#1593)

* Fix the 5.x dev Docker image workflow and make plugin branches resolvable

Start the Docker daemon on the AWS CodeBuild runners instead of pruning a
daemon that is not running, which aborted every scheduled run. Reduce the
schedule to a weekly build, add a plugins_branch input that falls back per
repository to the branch the workflow runs on when the branch does not exist
there, check out the requested branch in the build job, and let the inputs
default to the versions in package.json and .nvmrc.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Authenticate against Docker Hub before building the dev image

The build failed pulling node:22.22.0 with a 429 Too Many Requests: the AWS
CodeBuild runners share an IP pool that exhausts the Docker Hub anonymous pull
limit. Log in with the credentials the other build workflows already use.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Add diagnostics to the dev image build job

The build job died after 69 minutes with the build step still in progress and
no archived logs, so the failure cannot be read. Cap the job below the runner
reclaim window so GitHub stops it and keeps the logs, print the build with
plain progress, report memory, disk and kernel OOM kills after the step, and
stop the matrix from cancelling the sibling architecture.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Fall back to main when the workflow branch is missing in a plugin repository

The existence check only ran when plugins_branch was provided, so a run from a
branch of this repository that the plugin repositories do not have cloned a
non-existent branch. Walk the candidates in order - requested branch, workflow
branch, main - and use the first one that exists in each repository.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Raise the dev image build timeout to 90 minutes

With logs archived the build proved to need ~55 minutes of layers - 36 of them
in the optimizer warmup - plus the push to Quay.io, and it reports no OOM kills
and 100G of free disk. Give the job room to finish instead of cutting it in the
middle of the push.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Stop forcing the vfs storage driver on the Docker daemon

On the arm64 runner the daemon we start is the one that serves the build, and
vfs copies the whole filesystem on every layer: WORKDIR took 97s and a 1 KB
COPY took 19 minutes, against 0.2s and 0.1s on amd64, where a pre-existing
daemon on overlay2 answered instead. Reuse the running daemon when there is
one, let dockerd pick its driver otherwise, and keep vfs only as a fallback.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Pick the Docker storage driver by probing overlay stacking

Letting dockerd choose broke the arm64 job: it picked overlayfs and then failed
to mount, because / is an overlay mount on that runner and overlay does not
stack. Probe an overlay mount first, use the default driver when it works, try
fuse-overlayfs when it does not, and keep vfs as the last resort.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Build the dev image in a single expensive layer

Runners whose root filesystem is an overlay mount cannot stack overlay and fall
back to the vfs storage driver, which copies the whole tree on every layer.
Once /home/node/kbn holds node_modules that is about 19 minutes per layer, and
the checkout was followed by six of them - two WORKDIR, three COPY and two RUN
- which is over an hour of pure copying on the arm64 runner and free on amd64.
Copy the scripts before the checkout, where the tree is still empty, and run
the bootstrap, the plugin install and the optimizer warmup in one layer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Keep the image build output as an artifact

GitHub does not archive the log of a job it cancels, and the arm64 job is
cancelled by the timeout on every run, so three runs in a row left no trace of
which storage driver was chosen or how long each layer took. Tee the build
output to a file and upload it even when the step fails.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Drop the second stage of the dev image build

The stage existed to keep the intermediate layers out of the pushed image, but
the build is a single layer now and there is nothing left to drop. All it did
was copy /home/node/kbn in full - 320s on amd64, another whole-tree copy under
vfs - and chown every file in node_modules, which the git clone had already
created as node.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Raise the build timeout to 115 minutes

The CodeBuild runners now allow 120 minutes, but the job kept being cut at 90
by the workflow's own timeout, which was the lower of the two. Leave a margin
below the runner limit so GitHub is the one that stops a build that does not
finish, and the build log is uploaded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

* Set the build timeout to 120 minutes

Match the limit the CodeBuild runners now allow.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>

---------

Signed-off-by: Ian Yenien Serrano <ian.serrano@wazuh.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Diego García <82405377+Ripdiegozz@users.noreply.github.com>

* Keep the service user out of root's credential resolver paths (#1623)

The resolver runs as root from the maintainer scripts and ExecStartPre=+,
while /etc/wazuh-dashboard belongs to the service user. Three paths still
let that user steer root:

- --clear deleted dashboard.pem, dashboard-key.pem and root-ca.pem through
  the absolute ${CERTS_DIR} path, so a certs/ replaced with a symlink made
  root delete those names wherever it pointed, e.g. the shared CA anchor.
  It now enters certs/ as the issuing path does, removes relative to it,
  and refuses (and fails) when certs/ is not a real directory.

- The SAN list was written and read back through $(pwd -P)/<stage>/sans,
  which is resolved again through certs/ on each use. Swapping certs/
  between the two let the service user choose the names the shared CA
  signs. It is now built inside _dc_issue_pair, relative to the verified
  root-only staging directory.

- runuser kept the keystore and Node children in root's session and
  environment: from an interactive dpkg/rpm they could open root's
  terminal (TIOCSTI) and read what root exported, credentials included.
  Every child now goes through as_service_user: setsid (-w where
  util-linux has it) and env -i with only PATH and OSD_PATH_CONF.

The VM test matrix gains D22 (--clear with a symlinked certs/) and D23
(a node.options probe run from a terminal sees no tty and no root env).

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Restrict the not-ready healthcheck API to critical tasks and hide task data (#1624)

* Restrict the not-ready healthcheck API to critical tasks and hide task data

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Hide non-critical task errors on the not-ready server and escape the page output

- Replace the error of tasks that are not enabled and critical with a generic message, because it can carry node names and certificate details.
- Sort and dedupe the requested task names so reordered or repeated names share one run.
- Escape task names and errors on the not-ready page.
- Make the route test mocks return real task results so the checks exercise stored data.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

---------

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Hand the kept configuration over to root on RPM removal (#1625)

Removing the RPM package deletes the wazuh-dashboard user and group but
keeps /etc/wazuh-dashboard, whose certificates, private keys and keystore
stayed owned by the freed UID and GID. The next system account created
could inherit them and read those secrets.

Before the account goes, %postun now makes root the owner of everything
the account or its group owns in /etc/wazuh-dashboard, strips group and
other access, and reports what it kept, as the Wazuh indexer package
does. A kept /etc/default/wazuh-dashboard.rpmsave loses the group too.
A fresh install takes the directory back. The package test checks both.

Related: wazuh/wazuh-dashboard-plugins#9257

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Merge 4.14.10 into 5.0.0 (#1635)

Merge 4.14.9 into 4.14.10 (#1634)

* Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------




* Merge 4.14.8 into 4.14.9 (#1614)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

* Bump 4.14.8 branch (#1612)

feat: bump 4.14.8

---------




* Bump 4.14.9 branch (#1627)

feat: bump 4.14.9

* Change tag reference for 4.14.9 (#1629)

chore(tag-reference): change tag reference for 4.14.9

---------

Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>

* Fix Indexer management and Dashboards Management menu paths in docs (#1636)

* docs: fix Indexer management menu name on the read-only mode page

The read-only mode page named a Management menu that does not exist
in 5.0; the top-level category for indexer administration is Indexer
management (src/core/utils/default_app_categories.ts:76-82).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs: replace nonexistent Stack Management entry in Discover guide

getting_started_with_discover.md pointed to a 'Stack Management'
sidebar entry that doesn't exist in the Wazuh dashboard. The app is
titled Dashboards Management, under the Dashboard management category
(src/plugins/management/public/plugin.ts:84-86), with Data sources
(src/plugins/data_source_management/common/index.ts) as one of its
sections. Fix the same wrong label in the dsm_flow.puml diagram.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* docs: address review feedback on dashboard menu paths

- Rewrite the Discover data selector sub-steps as a real nested list;
  the plain a.-d. lines rendered as a lazy continuation of the S3 bullet.
- Drop the nonexistent "☰" label from the Dashboards Management path and
  note that the Wazuh dashboard hard-disables home:useNewHomePage, so the
  classic navigation always applies.
- Align the workspace "Data sources" tab casing.
- Replace the leftover "stack management" mention in user_stories.md.
- Rename the stale Page-Stack alias in dsm_flow.puml and regenerate
  dsm_flow.png from it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Fix the not-ready page false success notice (#1640)

* Show the not-ready success notice only after checks

The not ready page reported that no critical errors remain while the
health checks had not run yet, because only enabled, finished and failed
tasks counted. Show the success notice only once enabled tasks finished,
and a generic waiting notice otherwise.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Log the cause of bodyless indexer response errors

Responses without an OpenSearch error object, such as the security
plugin answering 503 or 401 with plain text, were logged as
"Response Error". Include the status code, the request method and path
and the bounded plain-text body so the cause shows in the server log.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Reword the not-ready waiting notice

The page cannot tell why the health checks have no results yet: the server may be waiting for the indexer, running saved object migrations or running the checks. State only that, and point to the logs.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Mark the Wazuh changes in the OpenSearch client

configure_client.ts and its test come from OpenSearch Dashboards. Keep the original code commented out and tag each Wazuh addition.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Fix the type of the bounded log line test

The collected log entry is typed string | Error, so reading .length broke the TypeScript project build (tsc -b tsconfig.refs.json) in the bootstrap step.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

---------

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* End the package install with how to log in (#1639)

feat(packages): end the install with how to log in

Print the dashboard URL, the admin login and the start command at the end of a fresh install. Show the certificate detail only with WAZUH_DASHBOARD_VERBOSE=1.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Bump 5.0.0 branch (#1645)

feat: bump 5.0.0

* Revert bump 5.0.0 branch (#1647)

feat: revert 5.0.0 references

* Bump 5.0.0 branch (#1650)

feat: bump 5.0.0

* Name the browser tab after the current app and add a skip link (#1643)

* fix(chrome): name the browser tab after the current app

Set the tab title to "<app title> - <applicationTitle>" on every app change instead of resetting it to the base title, so every plugin's app gets a distinct title. Fall back to Wazuh instead of OpenSearch Dashboards when applicationTitle is invalid.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* feat(rendering): add a skip to main content link

Render a skip link before the header, hidden until focused with Tab. Enter moves focus to the app wrapper without changing the URL hash, which the apps use for routing. Not rendered while the header is hidden, such as on the login page.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>

* Fix Timeline label regex blocking the server (#1652)

fix(timeline): run .label() regex with re2js to avoid ReDoS

A user-supplied .label() regex ran on native RegExp, so a nested quantifier could block the server's event loop. re2js runs in linear time and rejects backreferences and lookarounds.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* Minify the production bundles (#1646)

* feat(optimizer): minify the production bundles

Enable SWC compress and mangle for the optimizer bundles, which were
shipped with both disabled since the fork from Kibana.

Keep class and function names: code reads constructor.name (error
messages, error boundaries), and Babel compiles our classes to
functions, so keep_classnames alone does not protect them.

On a local amd64 package built from the same commits as the CI one,
the entry bundles shrink 38% decoded and 26% brotli, and the deb 3.3%.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* test(optimizer): update the dist bundle snapshot

The production bundles are now compressed and mangled, so the dist
snapshot of the foo and bar fixture bundles holds the minified code.

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

---------

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* Disable and reload the wazuh-dashboard systemd unit on RPM and DEB removal (#1654)

* fix(packaging): disable wazuh-dashboard systemd unit on RPM removal

systemctl stop in the %preun scriptlet left the unit enabled, leaving a
dangling multi-user.target.wants symlink and a not-found unit once the
RPM deleted the unit file. Mirror the DEB prerm and the wazuh-indexer
RPM by also running systemctl --no-reload disable before removal.

Closes #1653

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packaging): mirror the indexer's stop/disable/reload sequence in the RPM and DEB packages

The RPM %preun already stops and disables the unit, but nothing told
systemd to forget it once the unit file was actually removed, so
systemctl list-units could keep reporting it as not-found until some
unrelated reload happened. The DEB prerm disabled the unit without
--no-reload, and its postrm never reloaded either. Add the matching
daemon-reload to %postun/postrm, and --no-reload to the DEB disable
call, exactly as the wazuh-indexer RPM and DEB packages already do.

Closes #1653

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packaging): add --no-reload to the RPM stop call, matching the indexer

The DEB prerm and the wazuh-indexer RPM both suppress the reload on
stop since disable (right after) reloads once anyway; the dashboard
RPM's stop call was missing that flag.

Closes #1653

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

* fix(packaging): add --no-reload to the RPM's upgrade stop call too

%pre stops the running service before an in-place upgrade, same as
%preun does before removal. The wazuh-indexer RPM suppresses the
reload there too, since the unit file isn't changing yet.

Closes #1653

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>

---------

Signed-off-by: Antonio David Gutiérrez <antonio.gutierrez@wazuh.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* Rename wazuh-wui to wazuh-internal-client (#1651)

Signed-off-by: Federico Rodriguez <federico.rodriguez@wazuh.com>

* Configura CA validation by default (#1660)

* Merge 4.14.10 into 5.0.0 (#1671)

Merge 4.14.9 into 4.14.10 (#1664)

* Merge 4.14.8 into 4.14.9 (#1600)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

---------




* Merge 4.14.8 into 4.14.9 (#1614)

* Merge pull request #1507 from wazuh/change/1506-add-dev-image-construction-in-4x

Add dev image build tooling for 4.14.x

* Bump 4.14.8 branch (#1576)

feat: bump 4.14.8

* Update tag references to 4.14.8 in dashboard build workflows (#1577)

* Changelog not in descending chronological order (#1584)

* Reorder rpm changelog

* Change workflow tags

* Update tag references to 4.14.8 in dashboard build workflows (#1585)

* Update changelog (#1590)

* Bump 4.14.8 branch (#1597)

feat: bump 4.14.8

* Change references to 4.14.8 (#1598)

* Bump 4.14.8 branch (#1612)

feat: bump 4.14.8

---------




* Bump 4.14.9 branch (#1627)

feat: bump 4.14.9

* Change tag reference for 4.14.9 (#1629)

chore(tag-reference): change tag reference for 4.14.9

* Bump 4.14.9 branch (#1656)

feat: bump 4.14.9

* Change tag reference for 4.14.9 (#1657)

chore(tag-reference): change tag reference for 4.14.9

---------

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>
Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
Co-authored-by: Antonio <34042064+Desvelao@users.noreply.github.com>

* Merge 4.14.11 into 5.0.0 (#1686)

Bump 4.14.11 branch (#1663)

feat: bump 4.14.11

Co-authored-by: Wazuh CI <22834044+wazuhci@users.noreply.github.com>

* Rework the wazuh-dashboard 5.0 package (#1678)

* Open the wazuh-dashboard 5.0 package rework integration branch

Integration branch for #1670. The sub-issue PRs target this branch.

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Make /etc/wazuh-dashboard root-owned (#1674)

* Rewrite the dashboard credential resolver in Node

Replace the shell resolver and the shared lib/wazuh-credentials.sh with
resolve-credentials.js, run on the bundled Node by a short launcher. It
follows the per-package model: own CA in ca/, export/ca.pem, values from
the environment, local.env and the peers' export/ directories, and never
touches /etc/wazuh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Use the Apache-2.0 license header in the resolver launcher

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* fix(packaging): make /etc/wazuh-dashboard root-owned

Install the configuration directory as root:wazuh-dashboard so the
service reads its configuration, keystore and TLS material through its
group and can no longer rewrite them.

- DEB postinst and RPM %post stop handing the directory to the service
  account and run the ownership block from #1666 before the resolver
  (and, on DEB, before the upgrade restart), which also takes back an
  RC1 directory and accepts one staged by the operator. No step follows
  a symbolic link.
- The keystore is set to root:wazuh-dashboard 0640.
- DEB rules and RPM %files ship the directory, opensearch_dashboards.yml
  and node.options as root:wazuh-dashboard.
- The VM test matrix asserts the new layout on fresh install, operator
  staging and upgrade.

Refs: #1666
Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* chore(packaging): trim config ownership comments

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

* test(packaging): drop the root-ca.pem check from the upgrade case

Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>

---------

Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Signed-off-by: Diego Garcia <diego.garcia@wazuh.com>
Co-authored-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Ian Yenien Serrano <63758389+yenienserrano@users.noreply.github.com>

* Bind port 443 through a systemd ambient capability instead of setcap (#1675)

* fix(packages): bind port 443 through a systemd ambient capability

Grant CAP_NET_BIND_SERVICE from the unit instead of setcap on the bundled node binary, and drop the libcap2-bin and libcap dependencies.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

* fix(packages): reload the unit on upgrade and check the 443 bind in CI

Run daemon-reload on every DEB configure and in RPM %posttrans, so a stopped or restarted service starts with the new unit. CI package tests now wait for the 443 listener and check the unit-granted capabilities; the VM matrix also asserts CapAmb and CapBnd.

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>

---------

Signed-off-by: Rodrigo Lopez <rodrigo.lopez@wazuh.com>
Signed-off-by: Ian…
# Conflicts:
#	.github/workflows/4_builderpackage_dashboard.yml
#	dev-tools/build-packages/config/wazuh-dashboard
#	dev-tools/build-packages/credentials/README.md
#	dev-tools/build-packages/credentials/resolve-credentials.js
#	dev-tools/build-packages/credentials/resolve-credentials.test.js
#	dev-tools/build-packages/deb/debian/changelog
#	dev-tools/build-packages/rpm/wazuh-dashboard.spec
#	src/core/public/healthcheck/service.test.ts
#	src/plugins/healthcheck/public/components/button_header/health_check_nav_button.test.tsx
#	src/plugins/healthcheck/public/components/button_header/health_check_nav_button.tsx
The rework of the 5.0 package (#1678) replaced resolve-credentials.sh
with resolve-credentials.js and simplified build-packages.sh and the
deb postrm, but earlier upward merges into main kept the old pieces.
Take the 5.0.1 state for them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@yenienserrano
yenienserrano merged commit ef5c04e into main Nov 6, 2026
11 of 14 checks passed
@yenienserrano
yenienserrano deleted the merge-5.0.1-into-main branch November 6, 2026 16:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants