**Ticket:** Extend `receiverhelper` to allow scrapers to return `MetricSlice` or `ResourceMetricsSlice`

**Context**
The `receiverhelper` package currently offers a single `AddScraper` path, where the scrape callback returns a fully assembled `pdata.Metrics`. This forces every scraper to manually construct the outer `ResourceMetrics` and `InstrumentationLibraryMetrics` wrappers, even when the scraped data naturally takes the form of a flat `MetricSlice` or a `ResourceMetricsSlice`.

**Request**
Add two new public scraper-adding functions:

1. A function (e.g., `AddMetricsScraper`) that accepts a scrape callback returning `(pdata.MetricSlice, error)`. Internally, the helper should wrap the returned slice into a valid `pdata.Metrics` (with a single default resource and instrumentation library) and pass it to the configured `MetricsConsumer`.

2. A function (e.g., `AddResourceMetricsScraper`) that accepts a scrape callback returning `(pdata.ResourceMetricsSlice, error)`. The helper should convert the slice directly into `pdata.Metrics` and forward it to the consumer.

Both new scraper types must:
- Accept the same `ScraperConfig` and `ScraperOption` options as the existing mechanism (including initialize/close hooks and per-scraper or default collection interval).
- Follow the same error contract: when the scrape callback returns an error, nothing is forwarded to the consumer.
- Respect the stop signal so no further scraping occurs after the receiver is shut down.

The behaviour of the downstream consumer does not change; all conversion remains inside the helper.

The old `AddScraper` (and the associated `Scrape` type) should be removed, and any callers within the repository should be migrated to the new functions.

**Acceptance**
- Scrapers that return a `MetricSlice` work end-to-end: they are initialized, their scrape callback is invoked on the configured interval, and the resulting metrics are consumed by the `MetricsConsumer`.
- Scrapers that return a `ResourceMetricsSlice` work end-to-end in the same manner.
- Initialize/close errors are aggregated and returned as before.
- If a scrape returns an error, no data is consumed for that tick.

Extend receiverhelper scraper functions to simplify use of scrape (scrape metrics slice or resource metrics slice instead of having to return a metrics data object) (#1890)


**Implementer:**

The testbed’s agent readiness health check currently hardcodes `"tcp"` when dialing the sender's endpoint. This blocks testing receivers that use UDP (e.g., a syslog input). Please change the health check to dial using the sender’s actual network type (`tcp` or `udp`) so that UDP-based senders can be supported.

To make this work, the `DataSender` interface and its `GetEndpoint` method need to carry the network type alongside the address. All existing callers that used the endpoint as a plain string (for example, exporter configuration) will need to extract just the address portion. The base implementation can continue to assume `tcp` as a default when no other network is specified.

testbed: Support UDP in addition to TCP for agent health check (#2633)


The batch processor’s metrics handling still uses the deprecated `internal/dataold` representation and the corresponding `pdatautil.MetricsFromOldInternalMetrics` / `MetricsToOldInternalMetrics` conversion helpers. Migrate the batch metrics path to the current `internal/data` representation and the matching `pdatautil` conversion functions (`MetricsToInternalMetrics` / `MetricsFromInternalMetrics`). Update all test helpers and test data generation to use the new types and accessors (e.g. call `Name()` directly on a metric instead of going through `MetricDescriptor().Name()`). No observable change in batching behaviour is expected; the old `dataold` import should be completely removed from the batch processor package.

Change batch processor to use the new internal metrics structs (#1699)


**Title:** Metrics servers and OpenCensus registry leak when service initialization fails

**Description**
When the collector's service fails to initialize its extensions or pipelines (e.g., due to a configuration error), the HTTP server that serves own-telemetry metrics remains listening. This prevents the process from releasing the bound address and leads to port conflicts on retry. The underlying OpenCensus metric registry is also left registered as a global metric producer, leaking resources.

**Context**
During service creation (`service.New`), telemetry is initialized in two stages:
1. A `telemetry.Telemetry` object is created to provide the logger and tracer provider.
2. A separate `telemetryInitializer` creates the actual `metric.MeterProvider`, along with an OpenCensus registry (for process metrics) and one or more HTTP servers created by metric readers.

If the subsequent pipeline/extension initialization fails, only `telemetryInitializer.shutdown()` is called. The `telemetry.Telemetry` object (and therefore its tracer provider) is **not** shut down, and the meter provider that was placed into `TelemetrySettings.MeterProvider` is never shut down – so its underlying resources (OpenCensus producer, HTTP servers) are not cleaned up.

**Expected behavior**
- The meter provider returned to the rest of the service (and eventually to components) should **own** the OpenCensus registry and any HTTP servers that were created for metric readers. Shutting down that meter provider (by checking whether it implements the SDK’s `Shutdown(context.Context) error` interface) must:
  - Remove the OpenCensus registry from the global metric producer.
  - Close all associated HTTP servers.
  - Call the underlying SDK meter provider’s Shutdown.
- All service shutdown paths (both the final `Shutdown` call and the error-return path during `New`) must attempt to shut down the meter provider **and** the tracer provider via the same cast-to-shutdownable pattern.
- The separate `telemetryInitializer` struct should be eliminated; its responsibilities should be folded into the initialization of the meter provider so that lifecycle management is not duplicated.

This will ensure that when the collector fails to start, all telemetry infrastructure is torn down correctly, preventing port leaks and resource buildup.

[service] Replace telemetryInitializer by MeterProvider wrapper (#9454)


**Feature Request: Add Server Authentication Support for HTTP Receivers**

**Problem**
The OpenTelemetry Collector currently supports authentication for gRPC servers via the `configauth.Authentication` configuration and the `configauth.ServerAuthenticator` interface, but this capability is missing for HTTP servers built with `confighttp.HTTPServerSettings`. As a result, OTLP/HTTP receivers (and any other HTTP-based receiver) cannot be secured with the same authenticator extensions that are available for gRPC receivers. This creates a security gap and an inconsistent user experience between the two transport protocols.

**Expected Behavior**
1. `HTTPServerSettings` should accept an optional `Authentication` configuration (e.g., `Auth *configauth.Authentication`) so that users can specify an authenticator extension for HTTP servers, just as they do for gRPC servers.
2. When an authenticator is configured, every incoming HTTP request must be intercepted before reaching the handler. The authenticator should examine request metadata (e.g., headers) and either reject the request with an HTTP 401 Unauthorized status or attach authenticated context information to the request before passing it to the next handler.
3. The `configauth.ServerAuthenticator` interface should be extended with a method that provides an HTTP middleware / interceptor, analogous to the existing gRPC stream and unary interceptors. A default implementation of this interceptor should be provided (similar to `DefaultGRPCUnaryServerInterceptor` and `DefaultGRPCStreamServerInterceptor`) that calls the `Authenticate` function with the request headers and applies the same context propagation pattern.
4. The test mock (`MockServerAuthenticator`) should also implement the new HTTP interceptor so that users and receiver developers can write tests that verify HTTP authentication behavior.

**Impact**
- Users will be able to protect their HTTP receivers with the same authenticator extensions they already use for gRPC receivers.
- The collector’s security model becomes protocol-agnostic, matching the existing approach for `configgrpc`.
- This enables OTLP/HTTP to be deployed in environments that require authenticated endpoints.

`configauth`: add ServerAuthenticator interfaces for HTTP receivers (#4506)


We recently enhanced the confmap library to support unmarshaling embedded structs via `mapstructure:",squash"` tags (see the `unmarshalerEmbeddedStructsHookFunc` in `confmap/confmap.go`). This feature allows embedded structs with their own `Unmarshal(*confmap.Conf)` methods to be correctly decoded without the parent needing a custom `Unmarshal` to manually invoke child unmarshalers.

The `cmd/mdatagen` tool currently works around the lack of embedded struct support by implementing custom `Unmarshal(*confmap.Conf)` methods on the `gauge` and `sum` types in `cmd/mdatagen/metricdata.go`. These custom methods explicitly call the child `Unmarshal` methods and then use `parser.Unmarshal(d, confmap.WithIgnoreUnused())` to handle the remaining fields. This was necessary before, but is now redundant and complicates the code.

**Request:**
Refactor the mdatagen metric data types (`gauge`, `sum`, and any related structures) to use the now-supported embedded struct unmarshaling. Specifically:

- Remove the custom `Unmarshal(*confmap.Conf)` methods from `gauge` and `sum`.
- Change the `mapstructure` tags on embedded fields within these structs to use `squash` so that the confmap library handles decoding automatically.
- Ensure that any validation (e.g., required fields, valid enum values) that was inside the custom `Unmarshal` methods is properly moved into the respective child types' `Unmarshal` methods or struct tags, so that loading metadata YAML files still produces the same errors in terms of content, though the error *wrapping* (extra nested layers like `error decoding 'value_type'`) may become simpler and more direct.

The goal is to simplify the mdatagen unmarshaling code without changing the semantics of metadata loading: the same YAML inputs should be accepted or rejected as before, and the error messages should still clearly indicate invalid fields and values.

Acceptance criteria:
- The custom `Unmarshal` methods on `gauge` and `sum` are removed.
- Embedded structs use `mapstructure:",squash"` where appropriate.
- Required-field checks and value validation are handled within each embedded type's own `Unmarshal` method, without relying on parent types to orchestrate them.
- All existing mdatagen tests pass (after updating expected error strings if the error nesting level changed).
- No functional regression in the generated metadata code for collector components.

[chore] Refactor mdatagen unmarshaling to use less custom Unmarshalers (#9760)


We need a way to reconstruct `pdata.Traces` from serialized OTLP protobuf bytes.

**Problem**
The `pdata.Traces` type provides `ToOtlpProtoBytes()` to serialize trace data into an `ExportTraceServiceRequest` protobuf. There is no inverse operation: given a `[]byte` that contains an `ExportTraceServiceRequest`, you cannot populate an existing `Traces` with that data. This asymmetry prevents round-tripping traces through protobuf (e.g., when receiving OTLP/HTTP payloads, loading from durable storage, or re-materializing after marshalling).

**Expected**
Add a `FromOtlpProtoBytes(data []byte) error` method on `pdata.Traces` that:
- Unmarshals the `data` as an `ExportTraceServiceRequest` using Protobuf deserialization.
- Overwrites the receiver's contents with the resulting resource spans.
- Returns a non-nil error if the bytes are not a valid protobuf message.

**Safety / Edge Cases**
- A zero-value `Traces` (i.e., `var td Traces` without calling `NewTraces`) has an uninitialized internal pointer. Calling `FromOtlpProtoBytes` on such a receiver will panic. This is acceptable provided the method clearly documents that callers must pass a `Traces` created by `NewTraces` or otherwise already initialized.
- The method should replace any existing data in the receiver, matching the semantics of a deserialize-into operation.

**Impact**
Without this, consumers that receive traces as serialized OTLP protobuf cannot easily materialize them into the standard `pdata.Traces` representation for further processing or exporting. This is a basic building block needed for OTLP/HTTP ingestion and durable trace storage.

Add unmarshalling for pdata.Traces (#1948)


**Bug Report: Connectors in the collector configuration are not validated**

The `connectors` section of the OpenTelemetry Collector configuration is currently ignored during validation. When the `otelcol.enableConnectors` feature gate is enabled (or when connectors are otherwise supported), the collector should enforce the same level of config correctness as it does for receivers, exporters, processors, and extensions.

**Observed problems**

1. **Connector configs are never validated.**
   An invalid connector configuration (one that fails its `Validate()` method) is silently accepted, and the collector starts without any error.

2. **ID collisions are not detected.**
   A connector can share the same component ID as an existing receiver or exporter. This leads to ambiguous references and unexpected runtime behavior.

3. **Connector pipeline usage is not enforced.**
   A connector is supposed to act as both a receiver and an exporter at the pipeline level – it must be referenced as a receiver in one pipeline and as an exporter in a (possibly different) pipeline. Currently the collector does not check this constraint, so a connector can be used on only one side, which is a misconfiguration.

4. **References to unconfigured connectors are not caught.**
   If a pipeline references a connector ID that does not appear in the top-level `connectors` map, the error is not reported, or a confusing error about a missing receiver/exporter is produced.

**Expected behavior**

When connectors are enabled, the collector’s configuration validation (in `otelcol/config.go`) should:

- Validate every connector’s configuration using the standard `component.ValidateConfig` helper.
- Reject a connector whose ID collides with an existing receiver or exporter ID, with a clear error message indicating the collision.
- For each pipeline, recognize that a receiver or exporter reference may refer to a connector, not only to a configured receiver/exporter.
- After processing all pipelines, verify that each defined connector is indeed referenced as a receiver in at least one pipeline *and* as an exporter in at least one pipeline. If either role is missing, return an error stating that the connector must be used as both a receiver and an exporter.
- Ensure that references to connector IDs that are not configured are reported as `"not configured"` errors, consistent with how missing receivers/exporters are reported.

Additionally, the collector’s runtime setup (in `setupConfigurationComponents`) should be updated to use the validated connector configurations to build connectors, analogous to how receivers, processors, and exporters are built, so that the validated connectors are actually used.

**Impact**

Without this validation, misconfigured connectors slip through silently, leading to production issues that are hard to diagnose, such as dropped data, pipeline routing errors, or unexpected component behavior. This change adds the necessary safety net and aligns connector handling with the rest of the configuration.

Add connector validation to otelcol (#7001)


The OTLP HTTP exporter's default configuration currently overrides the connection‑pool settings that `confighttp.NewDefaultClientConfig` provides. After an earlier change meant to preserve backward‑compatibility, the exporter sets `MaxIdleConns`, `MaxIdleConnsPerHost`, `MaxConnsPerHost`, and `IdleConnTimeout` to `nil` in its default config. This is unnecessary: `NewDefaultClientConfig` already populates those fields with the standard `http.Transport` defaults, and the downstream `ToClient` call uses those exact same defaults when the fields are left `nil`. However, as a result, anyone inspecting the default config sees `nil` for these values rather than the sensible defaults they will actually get at runtime.

Remove the explicit `nil` assignments so that the default configuration of the OTLP HTTP exporter reflects the same connection‑pool defaults that `confighttp.NewDefaultClientConfig` returns. The behaviour of the exporter must remain identical; only the serialised and in‑memory config representation should change to surface the real defaults. Verify that after the fix, the default config shows the standard `http.DefaultTransport` values for the affected fields (e.g., `MaxIdleConns = 100`, `IdleConnTimeout = 90s`, etc.) instead of `nil`.

[exporter/otlphttpexporter] Remove unnecessary nil assignment in default client config (#11299)


Remove the duplicate fields and wrapper methods between the persistent queue and the contiguous storage backing it.

The persistent queue currently copies capacity, marshaler, unmarshaler, and holds a pointer to the storage, re‑exposing `Offer`/`Size`/`Capacity` with thin wrappers. This duplication causes drift and unnecessary indirection. Clean it up:

- Let the queue embed the storage directly so `Offer`, `Size`, and `Capacity` are promoted without extra methods.
- Remove the redundant fields (`capacity`, `marshaler`, `unmarshaler`, `storage`) from the queue struct.
- Compute the storage’s current size from `writeIndex - readIndex` under the existing lock, and drop the separate `itemsCount` atomic; this avoids two sources of truth for the same number.
- The `Offer` method on storage must accept and forward a `context.Context` to the underlying `Batch` call instead of discarding it and using `context.Background()`.
- The `stopStorage` helper (used for monkey‑patching in tests) should operate on a `storage.Client` interface, not the concrete `*persistentContiguousStorage`.
- Since the embedded storage needs the client at start time, separate construction from initialization: the constructor should not require a client; introduce a `start` step that sets the client and initialises the persistent state. The queue’s `Start` method should call this instead of constructing a fresh storage.

All existing behaviours around capacity enforcement, shutdown ordering, and item dispatch must remain unchanged.

[chore] remove duplicate members and funcs between persistent queue and storage (#8885)


**Title:** Inconsistent naming: `RegisterServer` should be `RegisterGRPCServer` to match `GRPCServer`

**Description:**

In a previous release the OTLP server interface type was renamed from `Server` to `GRPCServer` across the three signal packages (`plogotlp`, `pmetricotlp`, `ptraceotlp`). The old `Server` name was kept as a deprecated type alias. However, the corresponding registration function `RegisterServer` was not updated and still uses the short name, which is inconsistent with the rename and confusing for users.

For example, a user implementing the `GRPCServer` interface naturally expects a matching `RegisterGRPCServer` function, but must instead call `RegisterServer`.

**Expected behavior:**

- Add a new function `RegisterGRPCServer` in each of the three packages (`plogotlp`, `pmetricotlp`, `ptraceotlp`) that has the same behavior as the current `RegisterServer`.
- Keep `RegisterServer` available as a deprecated compatibility alias pointing to `RegisterGRPCServer`, matching the deprecation pattern already used for the `Server` → `GRPCServer` type alias.
- Update all internal call sites (production code and tests) in this repository to use `RegisterGRPCServer` instead of the deprecated `RegisterServer`.
- Note the deprecation in the unreleased section of `CHANGELOG.md` under a Deprecations heading.

**Impact:** Users referencing the deprecated name will still compile but will see deprecation notices guiding them to the new name. This keeps the public API consistent (`GRPCServer` registered via `RegisterGRPCServer`).

[pdata] Rename RegiserServer func to RegiserGRPCServer (#6182)


We should refactor the persistent queue internals in `exporterhelper` to reduce unnecessary memory allocations and simplify its storage layer.

The current implementation wraps every storage-client batch operation in a helper type that allocates extra slices, maps, and closures, and it duplicates serialization logic. That extra overhead can be removed by using the storage client’s batch API directly, without the intermediate helper. The queue–name field is also stored as a separate struct member when it is only needed for logging; it should be applied to the logger at construction time instead.

Acceptance criteria / invariants:
- All existing behaviour of the persistent queue must be preserved: enqueue/dequeue ordering, error handling, recovery of partially dispatched items on restart, capacity enforcement, and graceful shutdown.
- The storage client’s `Batch`, `Get`, `Set`, and `Delete` operations must be used directly rather than through the custom helper.
- Serialization of read/write indices and item identifiers must avoid extra allocations (e.g., using byte slices efficiently) and must correctly handle nil values (including `errValueNotSet` semantics).
- The separate `batchStruct` type and its associated methods should be removed entirely.
- The `queueName` string field should be removed from the persistent storage struct; logger context must still include the queue name.
- Edge cases in item dispatching must continue to work: if updating the dispatched-items list and deleting the item together in a batch fails, the code must fall back to deleting the item first and then retrying the dispatched-list update, with appropriate error reporting.
- The exported changelog entry type should be `enhancement` for the `exporterhelper` component.

persistentstorage: Simplify usage of storage client, avoid unnecessary allocations (#8830)


**Title:** Remove usages of deprecated `pdata` `Clone` methods

**Description:**
The `Clone()` methods on `ptrace.Traces`, `pmetric.Metrics`, and `plog.Logs` have been deprecated. We need to eliminate all direct calls to these methods in the repository and replace them with the currently recommended `New…` + `CopyTo` pattern.

**Acceptance Criteria / Behavior:**
1. No production or test code anywhere in the repository calls `.Clone()` on a pdata `Traces`, `Metrics`, or `Logs` value.
2. Every former clone site must use the equivalent copy semantics:
   - Create a new empty destination via the appropriate `ptrace.NewTraces()` / `pmetric.NewMetrics()` / `plog.NewLogs()` constructor.
   - Copy data into it via `src.CopyTo(dest)`.
3. The **fanout consumers** (`service/internal/fanoutconsumer`) must still pass an independent mutable copy to each consumer in the `clone` path so that one consumer cannot observe mutations made by another. The old implementation achieved this by cloning the original data on each iteration; any replacement must preserve that isolation guarantee.
4. In the **`pmetricotlp`** package, the `rawMetricsServer` struct currently uses the deprecated `Server` type alias for its `srv` field. This should be changed to `GRPCServer` (the canonical interface name) to match how the analogous raw servers for traces and logs are typed and to avoid reliance on the alias.
5. Test assertions that previously depended on cloning for later comparison should instead keep a copy of the relevant data path (or drop the clone if the assertion can safely use the original in-memory value now that the underlying transport no longer mutates it).

**Affected areas (non-exhaustive):**
- `exporter/otlpexporter` – helper that snapshots received data
- `processor/batchprocessor` – several tests that build expected datasets
- `receiver/otlpreceiver` – test helpers for OTLP export that previously cloned for comparison
- `service/internal/fanoutconsumer` – three consumer implementations that copy for clone-path consumers
- `pdata/pmetric/pmetricotlp` – server struct field type

**Notes:**
- Do not introduce a reliance on the deprecated `Clone` function or its semantics.
- Running the existing test suite should pass after the migration.

Remove usages of deprecated pdata Clone methods (#6170)


**Title:** Refactor batch processor internals with generics to eliminate `any` and type assertions

**Background**
The batch processor currently uses `any` for data items throughout the core batching logic. The concrete batch implementations for traces, metrics, and logs all perform manual type assertions in methods like `add`, `export`, `splitBatch`, and `sizeBytes`. With Go generics now available, we can make the batch processor parameterized over the concrete data type and remove these unsafe casts, improving compile-time type safety without changing any runtime behavior.

**Request**
Convert the batch processor and its supporting types to be generic over the data type (e.g., `ptrace.Traces`, `pmetric.Metrics`, `plog.Logs`). Specifically:

1. Make `batchProcessor`, `batcher`, `shard`, and `batch` interfaces/structs generic so that the item type flows through the entire batching pipeline without `any`.
2. Update the signal-specific batch implementations (`batchTraces`, `batchMetrics`, `batchLogs`) to implement the generic `batch` interface with their concrete types, removing all type assertions.
3. Remove the `ConsumeTraces`, `ConsumeMetrics`, and `ConsumeLogs` methods from the generic batch processor. Instead, introduce signal-specific wrapper types that embed the generic batch processor and implement the corresponding `processor.Traces`, `processor.Metrics`, and `processor.Logs` interfaces. These wrappers should delegate to the generic `batcher.consume`.
4. Update the existing constructor functions (`newBatchTracesProcessor`, `newBatchMetricsProcessor`, `newBatchLogsProcessor`) to return the new wrapper types. The factory (`factory.go`) should continue calling these constructors.
5. Ensure `newBatchProcessor` becomes a generic function that receives a `batchFunc` producing the correct type of batch, and that `multiShardBatcher` correctly handles the typed shards stored in its `sync.Map`.

**Constraints**
- Do **not** alter any existing batch processing logic (size limits, timeout behavior, metadata sharding, split rules, metric/trace/log count tracking).
- All current batch processor tests must continue to pass unchanged, except for adjustments to constructor names if the public API surface changes.
- The generic struct must no longer directly implement `consumer.Traces`, `consumer.Metrics`, or `consumer.Logs` — those interface satisfactions move to the new wrapper types.

[chore] Small nits in batch processor, use generics to avoid type conversions (#11501)


Title: Remove "Get" prefix from recently added methods on `featuregate.Gate` where possible

In the `featuregate` package, the `Gate` type has several accessor methods. A few of them (`GetStage`, `GetReferenceURL`, `GetRemovalVersion`) were recently introduced and use a `Get` prefix that is unidiomatic in Go. Since these methods do not conflict with any exported struct fields, the prefix should be dropped to follow standard Go naming conventions.

Rename the following methods on `Gate`:
- `GetStage` → `Stage`
- `GetReferenceURL` → `ReferenceURL`
- `GetRemovalVersion` → `RemovalVersion`

Do **not** rename `GetID` or `GetDescription` at this time, because those conflict with the exported fields `ID` and `Description` on the same struct; a future change will address them after the fields are removed or made unexported.

Update all internal callers and tests to use the new method names. No deprecation is necessary since the old names were only added in the current development cycle and have not yet been part of a release.

Remove get from newly added funcs on Gate that don't conflict (#6485)


Add an `Auth` field to `client.Info` that carries authentication data from authenticators to downstream components.

Define an interface with methods `GetAttribute(string) interface{}` and `GetAttributeNames() []string` to represent arbitrary auth attributes. The data should be produced by authenticators, stored into `client.Info` via `NewContext`, and consumed by processors and exporters.

Ensure that the existing constructors `FromGRPC` and `FromHTTP` continue to compile cleanly after the struct extension (they currently use positional struct literals; update them as needed).

Update the package documentation to describe the new flow: authenticators are responsible for obtaining the client info, populating the `Auth` field, and injecting the updated context; downstream components can read attributes by name and should document which attribute names they expect. Provide a configuration snippet showing how a hypothetical processor would reference an attribute produced by an authenticator.

Add a testable example (`Example_authenticator`) that shows an authenticator enriching `client.Info` with auth data and returning a new context.


**Request: Include auto-generated resource attributes in collector's own stdout logs**

### Problem
The collector automatically generates resource attributes such as `service.name`, `service.version`, and `service.instance.id` when they are not set in the telemetry resource configuration. These generated attributes become part of the resource for exported telemetry, but they are **missing** from the collector's own console (stdout) log output. Only resource attributes that were explicitly configured appear in the `resource` field of stdout log records. This makes it harder to identify, filter, and correlate collector log entries in default configurations.

### Acceptance criteria
1. **Default resource attributes appear in stdout logs**
   When no resource configuration is provided, the JSON log records written to stdout must contain a `resource` object that includes the generated `service.name`, `service.version`, and a generated `service.instance.id` value.

2. **User-configured resource overrides are respected**
   If the user explicitly sets `service.name` (or any other resource attribute) in the configuration, the stdout log `resource` object must reflect the user-provided value, not the auto-generated default. Example: setting `service.name: "my-collector"` must cause `"resource": {"service.name": "my-collector", …}` in the logs.

3. **Additional user resource attributes are included**
   Any custom resource attributes defined in the configuration (apart from the semantic convention keys) must appear in the stdout log `resource` object alongside the generated attributes.

4. **No duplication in exported OTLP logs**
   The resource attributes added to stdout log records must not be attached to the Zap logger itself; they must be added to the stdout core only. The same resource attributes that are part of the exported OTLP logs must not appear a second time on the log body or attributes when the same log entry is exported through the `LoggerProvider`. In other words: the resource fields on stdout and the resource on exported OTLP logs must remain consistent and not be double-applied.

### Notes
- The effective resource after applying automatic generation (command-based service name, build version, instance ID) is already assembled at startup. Use that effective resource rather than the raw configuration map.
- The collector's stdout output format is JSON (when using the default encoding); verify that the `resource` field in each log entry is a structured object containing the attributes described above.
- This change should not affect the resource on exported OTLP logs beyond ensuring they remain correct and un-duplicated.

Print generated resource attributes for internal logs (#13111)


**Title**: Support programmatic override of HOST_PROC for process telemetry in container environments

**Description**:

When running the OpenTelemetry Collector inside a Kubernetes pod where the `HOST_PROC` environment variable is set to a host-level path (e.g., `/hostfs/proc`), startup fails with:

```
Error: failed to register process metrics: process does not exist
```

The underlying library (gopsutil) respects `HOST_PROC` and tries to locate the collector’s PID on the host’s `/proc` filesystem. In the container, that process only exists in the container’s own `/proc`, so the existence check fails and registration returns an error.

**Request**:

Provide an option on the process-metrics registration path that supplies an explicit `/proc` root directory. When set, this value should be used by all subsequent gopsutil calls that query process information (CPU, memory, etc.) for the lifetime of those metrics, ignoring the `HOST_PROC` environment variable.

**Acceptance criteria**:

1. The public function that registers process metrics (`RegisterProcessMetrics`) accepts an optional argument representing a custom host-proc path.
2. When a custom path is provided, the collector bootstraps correctly in container environments where `HOST_PROC` points to a host path, and all reported process metrics (CPU seconds, RSS memory, uptime) are based on the given path rather than `HOST_PROC`.
3. When no custom path is provided (or it is empty), existing behaviour is preserved—the environment variable `HOST_PROC` and the library’s default (`/proc`) continue to be used, keeping backward compatibility.
4. Existing callers of `RegisterProcessMetrics` (including those inside the collector’s own telemetry initialization) require no changes and continue to work.
5. The override works on Linux; behaviour on other platforms remains unaffected.

**Additional context**:

The bug manifests only when the environment variable `HOST_PROC` is present and set to a path that does not contain the container’s own process tree. A programmatic override allows the collector (or its embedders) to explicitly point to `/proc` without unsetting the environment variable, solving the startup failure without side effects for other components that may depend on `HOST_PROC`.

[service/proctelemetry] Offer to override the HOST_PROC environment variable with a programmatic value (#7998)


The Kafka exporter still relies on its own OTLP protobuf marshaler implementations (`otlpTracesPbMarshaler`, `otlpMetricsPbMarshaler`, `otlpLogsPbMarshaler`) that directly call `ToOtlpProtoBytes` and encode the result into Sarama messages. Meanwhile, the project has introduced a `model.Marshaler` abstraction in `internal/model` along with a shared protobuf implementation in `internal/otlp` (functions `NewProtobufTracesMarshaler`, `NewProtobufMetricsMarshaler`, `NewProtobufLogsMarshaler`). The logging exporter already uses these new marshalers, but the Kafka exporter is behind, leading to code duplication and inconsistency across components.

**Problem**:
When the Kafka exporter is used with the default `otlp_proto` encoding, it does not use the centralized protobuf marshalers. This means any bug fixes or improvements to the shared OTLP marshaler won't automatically benefit the Kafka endpoint, and the exporter contains redundant marshaler code.

**Expected behavior**:
The Kafka exporter should use the common protobuf marshalers from `internal/otlp` for its default OTLP encoding, adapting them to implement the exporter's own `TracesMarshaler`, `MetricsMarshaler`, and `LogsMarshaler` interfaces (i.e., converting pdata structs to bytes and wrapping them in `sarama.ProducerMessage`). The custom OTLP marshaler types can be removed, and any tests that construct those types directly should be updated to use the new adaptation. The external behavior (output messages, encoding name) must remain unchanged.

Use the new marshaler/unmarshaler in Kafka exporter (#3403)


```markdown
Title: Update cloud resource attribute names per latest OTel specification

Background:
The OpenTelemetry specification recently renamed two cloud resource attributes:
- `cloud.zone` → `cloud.availability_zone`
- `cloud.infrastructure_service` → `cloud.platform`

We need to align our implementation with these changes (see spec PRs #1495 and #1530).

What to do:
- Update the exported semantic convention constants: rename the Go identifiers and string values for `cloud.zone` and `cloud.infrastructure_service` (including the platform-specific value constants like `aws_ec2` etc.).
- Ensure any internal usage of these constants (e.g., golden dataset generators) reflects the new attribute names.
- Update the resource processor’s documentation (README) and its example YAML configuration to use `cloud.availability_zone` instead of `cloud.zone`.
- OpenCensus backward compatibility: when converting an OpenCensus resource into OTLP (and vice versa), the old OpenCensus label key for zone must be translated appropriately.
  * OC→OTel: map the known OC zone key to our new `cloud.availability_zone` attribute.
  * OTel→OC: map our `cloud.availability_zone` back to the OC zone key.
  This ensures agents still using the legacy OC label continue to work.

Acceptance criteria:
- All references to `cloud.zone` and `cloud.infrastructure_service` are replaced with the new attribute names in code and examples.
- The resource processor documentation and example configuration show the new attribute.
- OpenCensus ↔ OTLP conversion handles the zone key mapping correctly.
- Existing behavior around other attributes is unchanged.
```

Updates for cloud semantic conventions (#2809)


The Zipkin exporter does not expose `retry_on_failure` or `sending_queue` configuration, unlike several other exporters (e.g., Jaeger). Users need to configure retry with backoff and a buffered sending queue for reliability.

Add config support for `retry_on_failure` and `sending_queue` to the Zipkin exporter, wired through the standard `exporterhelper` mechanisms. The default configuration created by the factory should include the default retry/queue settings.

When testbed data senders (including `ZipkinDataSender`, `JaegerGRPCDataSender`, and OTLP-based senders) create exporters, they must push data synchronously from the caller goroutine, without any retry or buffered queuing. Ensure that any retry or queue features are explicitly disabled in those testbed sender configurations so that tests remain deterministic and do not depend on asynchronous delivery.

Add queue retry to zipkin exporter, and enable them (#1971)


We need to produce a bug report as if written before the patch. The bug: panic in the Prometheus remote-write exporter when a counter metric’s name is shorter than the expected suffix ("total" in the old code, length 5), because of unsafe slicing. Also the code had a spelling mistake "delimeter" instead of "delimiter". The fix replaced the slicing with `strings.HasSuffix` using the full `_total` suffix, which inherently handles any length. The bug report should describe that exporting a counter with a name shorter than 5 characters causes the collector to panic. Expected behavior: no panic; counter suffix added only if the name does not already end with `_total`. So:

Title: "Panic when exporting counter metric with short name via Prometheus remote write"

Body: explain the Prometheus remote write exporter appends `_total` to counter metric names when they don't already end with `total`. If a counter metric has a name shorter than 5 characters, the exporter crashes with an out-of-range panic. Example: a counter named "http" (length 4) would trigger the panic. The exporter should handle such names gracefully and not append the suffix if the name already ends with `_total`. Also note a typo: "delimeter" should be "delimiter" in constants.

We should not mention the exact line of code, but we can refer to the naming logic in the exporter. The natural way: "In the Prometheus remote write exporter, when converting OTLP counter metrics, a `_total` suffix is appended unless the metric name already ends with `total`..." That's sufficient.

We'll write the request as a GitHub issue-style bug report.**Title:** Prometheus remote-write exporter panics on counter metrics with short names

**Description:**
When exporting an OTLP‑based counter metric whose base name is shorter than 5 characters (e.g. `"a"`, `"abc"`, `"http"`), the Prometheus remote-write exporter crashes with an index‑out‑of‑range panic. This happens because the conversion logic tries to check whether the metric name already ends with the string `"total"` before appending `_total`, but the check uses unchecked slice indexing without guarding against names that are shorter than the suffix.

**Steps to reproduce:**
1. Create an OTLP counter metric with a name shorter than 5 characters (for example `"http"`).
2. Configure a pipeline that exports metrics via the Prometheus remote‑write exporter.
3. Send the metric and observe the collector crash / panic in the exporter.

**Expected behavior:**
- Short metric names should not cause a panic. The exporter should safely decide whether to append the standard Prometheus counter suffix.
- If the metric name already ends with `_total`, the suffix should not be appended again (e.g. a metric named `"requests_total"` should stay `"requests_total"`).
- The metric name sanitization and suffixing should work for any valid name length, including the edge case of a name that is exactly `"_total"` (though unlikely in practice).

**Additional notes:**
- There is a spelling mistake in the existing code where the constant `delimeter` is used instead of `delimiter`. This should be corrected alongside the fix.
- The logic should prefer a call that inherently handles empty or short strings, such as a standard “has suffix” check, rather than fragile manual slice‑indexing.

[prometheusremotewrite] fix: counter name check  (#2613)


**Title:** Expose `ConfigProviderSettings` in `CollectorSettings` so users can inject custom `confmap.Provider`s without implementing `ConfigProvider`

**Background**
Currently, the only way to supply a custom configuration provider (e.g., a custom `confmap.Provider` or custom `confmap.Converter`) to the Collector is to implement the full `otelcol.ConfigProvider` interface and set it on `CollectorSettings.ConfigProvider`.  The `CollectorSettings` struct already exists, and the `otelcol.ConfigProviderSettings` type (which wraps `confmap.ResolverSettings`) already exists, but there is no way to pass *settings* directly into the Collector – you must instead build a `ConfigProvider` yourself.

**Request**
Add a `ConfigProviderSettings` field to `CollectorSettings` that accepts `otelcol.ConfigProviderSettings`.  When a `ConfigProviderSettings` is provided and no `ConfigProvider` is given, the Collector should construct the internal `ConfigProvider` from those settings.  If a `ConfigProvider` is set, it should take precedence (backward compatibility).  Deprecate the `ConfigProvider` field.

**Acceptance Criteria / Observable Behavior**

1. **Direct settings without a custom ConfigProvider**
   If a user creates a `CollectorSettings` with `ConfigProviderSettings` populated (but no `ConfigProvider`), `otelcol.NewCollector` should build a `ConfigProvider` from those settings and use it internally.  The Collector should start, run, and shut down normally using that provider.

2. **Backward compatibility**
   If `ConfigProvider` is explicitly set on `CollectorSettings`, the Collector must use it and ignore any `ConfigProviderSettings`.  All existing code that only sets `ConfigProvider` should continue to work without modification.

3. **Integration with NewCommand / CLI flags**
   When using `otelcol.NewCommand`, the `--config` command-line flag(s) must be able to override the URIs specified in `ConfigProviderSettings.ResolverSettings.URIs`.  If the user specified custom providers or converters in the settings, those customizations should be preserved when the CLI overrides the URIs.
   If neither `ConfigProvider` nor `ConfigProviderSettings` is provided by the caller of `NewCommand`, the command must fall back to the existing default providers and converters (the same ones used today) and apply the `--config` URIs.

4. **No required config provider**
   The `NewCollector` function must not error out simply because `ConfigProvider` is `nil` when `ConfigProviderSettings` is present.  If neither is provided, or if the settings are invalid (e.g., missing required resolver fields), a descriptive error should be returned.

5. **Windows service support**
   The Windows service handler (`otelcol` package) should also respect `ConfigProviderSettings` when starting the Collector.  It should follow the same rules as the command path: CLI flags override URIs, custom providers/converters are kept, and if no `ConfigProvider` is given the settings are used to construct one.

6. **Graceful deprecation**
   `CollectorSettings.ConfigProvider` should be marked as deprecated (e.g., via a comment with the version), directing users to `ConfigProviderSettings`.

**Constraints / Non-goals**
- Do not change the public API of `ConfigProviderSettings`, `ConfigProvider`, `confmap.ResolverSettings`, or any existing public types beyond adding the new field and deprecation comment.
- The existing default providers/converters (file, env, yaml, etc.) must remain the fallback when no custom ones are specified, both for direct usage and for CLI-based usage.
- This request does not aim to remove `ConfigProvider` – only to allow an alternative that may eventually replace it.

[otelcol] Allow passing confmap.Providers to otelcol.Collector (#9228)


**Feature Request:** Implement blocking `Offer` mode for exporter queues

**Component:** `exporter/exporterqueue`

**Summary:**
Currently, when the queue is full, `Offer` returns `ErrQueueIsFull` immediately. We want an internal option (not yet configurable) to make `Offer` block until there is room for the item, similar to a bounded blocking channel. This will allow consumers to wait instead of dropping data.

**Details:**
- Add a `blocking` boolean field to the queue settings structs (`memoryQueueSettings`, `persistentQueueSettings`). When set to true, the queue should block in `Offer` if there is not enough capacity, waiting until space becomes available or the context is canceled. When false (the default), the existing behavior (return `ErrQueueIsFull` immediately) remains.
- The waiting mechanism must be context-aware: if the context is done before the item can be enqueued, `Offer` should return the context’s error (e.g., `context.Canceled` or `context.DeadlineExceeded`).
- When the queue’s size decreases — either due to successful reading (`Read`) or because `OnProcessingFinished` finally removes an item — any blocked producers should be woken to try again.
- The in-memory queue (`sizedQueue`) already uses `sync.Cond` to signal consumers when elements are available. A similar mechanism (but context-aware) should be introduced for producers waiting for space. The persistent queue also needs this.
- Ensure that calling `Shutdown` unblocks any waiting producers so they can exit gracefully.
- No changes to the public `Queue` interface are needed.

**Acceptance criteria:**
- When `blocking=true`, a producer that calls `Offer` on a full queue blocks until space is available and then succeeds (or returns an error if context is canceled).
- Concurrency tests with many goroutines producing and consuming confirm all items are eventually enqueued and consumed without deadlock.
- Existing non-blocking behavior is preserved.
- The new blocking logic is internal; no configuration surface is exposed yet.

Add capability for memory and persistent queue to block when add items (#12074)


**Title:** Synchronous blocking when batching is enabled but queue is disabled

**Component:** exporterhelper

**Problem:**
When an exporter is configured with batching enabled but queueing disabled (`queue.enabled: false`), the exporter behaves asynchronously: `Send` returns immediately without waiting for the batched request to be fully processed. Users who disable the queue to avoid memory buffering still expect backpressure—i.e., that the call blocks until the request is actually exported. The current implementation bypasses the queue entirely when it is disabled, causing the batcher to process requests asynchronously and `Send` to return before completion.

**Desired behavior:**
When batching is enabled, the exporter helper must always insert a queue between the caller and the batcher. If the queue configuration is disabled, this queue should be synchronous: it must call the batcher’s consumption function and then block until the consumption signals completion via its `Done` callback. The queue must not buffer requests; its capacity should be 0 (meaning unbounded conceptually, but in practice no items sit in the queue). It should track the number of in‑flight requests and respect context cancellation (returning the context error if the caller cancels before the export finishes).

**Constraints and edge cases:**
- The batcher already uses a `Done` callback; the synchronous queue must wait for exactly that signal. If the context is cancelled while waiting, the queue must not reuse the callback resources until the callback is actually invoked by the consumer (to avoid races).
- The batcher’s internal worker pool (currently a channel of size `queue.NumConsumers`) limits concurrency only when an async queue is in use. When the queue is synchronous (i.e., `maxWorkers == 0`), the batcher must **not** allocate a worker pool and must never attempt to acquire a worker token. Doing so would deadlock: the synchronous queue would be waiting for the batcher to accept, but the batcher would be waiting for a token from a pool that will never be filled.
- All other batcher behaviour (batching by size/time, merging, timer‑based flushing, shutdown draining) must remain unchanged.
- The exporter helper wiring must be adjusted so that a queue is created whenever batching is enabled, regardless of the `queue.enabled` flag. Only when both batching and queueing are disabled should the exporter skip the queue entirely.

**Acceptance criteria:**
- With batching enabled and `queue.enabled: false`, `Send` blocks until the request is processed.
- Errors from the export are propagated synchronously.
- Context cancellation during the wait is honoured and doesn’t leak internal resources.
- The batcher works correctly when `maxWorkers` is 0 (no async workers).
- The existing test `TestBatchSender_PostShutdown` for the “queue+batcher” path (currently commented out) can be re‑enabled once this change is in place.


**Title:** Fix compilation breakage after `pdata.StringValue` removal in filter expression code

**Background**
A recent update to the `pdata` library removed the `pdata.StringValue` type. `pdata.StringMap.Get` now returns `(string, bool)` directly, and the callback in `ForEach` receives a plain `string` as the value parameter instead of a `StringValue`.

**Observed symptom**
The collector no longer compiles because two places still use the old `StringValue` type and its `.Value()` method:
1. The filter expression matcher that creates label-access closures for metric matching.
2. The test helper that iterates over a `StringMap` to assert a metric was filtered out.

**Request**
Update both usages to match the current `pdata` API so the collector builds and all existing tests pass. Specifically:
- In the `Label` closure returned by the matcher’s `createEnv` helper, eliminate the call to `.Value()`; the value returned by `StringMap.Get` is already a `string`, so return it directly (fallback to empty string when not found).
- In the filtering test’s `ForEach` callback, change the value parameter type from `pdata.StringValue` to `string` and compare it directly against the expected label value without calling `.Value()`.

No behavioral changes are expected; this is purely an API migration fix. The existing `HasLabel` closure (which checks existence) remains correct.

**Additional notes**
There is an old comment suggesting `Label` and `HasLabel` could eventually be merged into a `GetLabel` that returns `(string, bool)`, but that refactor is out of scope. For now, just restore compilation by adapting to the new signatures.

Fix usage of removed pdata.StringValue, PR merged after the remove (#2034)


Feature: Environment variable expansion in default component configurations

`CreateDefaultConfig` (for receivers, exporters, processors, extensions) may now return string fields that contain environment variable references (e.g., `$DD_ENV`). These references should be expanded automatically when the collector loads a component's default configuration, using the same rules that already apply to YAML configuration values:
- `$VAR` is replaced by the value of the environment variable `VAR`.
- `$$VAR` is replaced by the literal `$VAR`.
- Missing variables are replaced by an empty string.

**Important:** the expansion must happen on the default config struct **before** the user-provided configuration is merged on top. This prevents accidental modification of user-supplied values and ensures only the default values are subject to expansion.

**Scope and safety constraints:**
- Apply expansion recursively to all exported string fields (including `*string` fields and string fields inside nested structs/pointers).
- Unexported fields must be left unchanged.
- Passing a `nil` config pointer must be handled safely (no-op).
- The expansion should be applied in the same places where default configs are created for receivers, exporters, processors, and extensions during config loading.

[config] Default config env variable expansion (#2231)


```
Make stability-level logging available for extensions as well.

Currently, during pipeline construction (receivers, processors, exporters)
a dedicated function logs the stability level of each component so that
operators are warned about unstable components. Extensions (e.g. health
check, zpages) are built separately and do not log these warnings.

We need:
- A method on `StabilityLevel` that returns a descriptive log message for
  each level (unmaintained/deprecated/in-development/alpha/beta/stable).
- The existing stability-logging logic moved to a shared internal package
  (somewhere under `service/internal`) so it can be reused by both pipeline
  building and extension building.

The logging behaviour should remain:
- Unmaintained, Deprecated, InDevelopment, Undefined → Info level
- Alpha, Beta, Stable → Debug level
```

add LogMessage and move LogStabilityLevel (#5633)


**Feature Request: Lock down metadata settings and key creation**

As a system administrator, I need a server-level configuration option that prevents any modification of metadata settings and creation of metadata keys through the API, so that once the metadata is configured, even administrative API access cannot change it.

**Acceptance criteria**

- A new environment variable `PASSBOLT_SECURITY_METADATA_SETTINGS_EDITION_DISABLED` is available.
- When set to `true`, the following endpoints return a `403 Forbidden` response with the message `"Metadata settings endpoints are disabled."`:
  - `PUT /metadata/settings` and `POST /metadata/settings`
  - `POST /metadata/keys`
- When the variable is absent, set to `false`, or set to any value that evaluates to `false`, those endpoints behave exactly as they do today (no change in functionality).
- The setting does not affect any other `/metadata` endpoints (e.g. `GET /metadata/settings`, `GET /metadata/keys`, session key routes).

PB-35272 Add server settings to prevent edition of metadata settings and key


The email digest sender command (`passbolt email_digest send`) processes queued notifications but never marks them as sent. After successful delivery the rows stay with `sent = false`, causing duplicate emails on subsequent runs and spurious failures.

**Root cause**: When `EmailPreviewFactory` assembles a digest from one or multiple email queue entities, the resulting `EmailDigest` object does not carry the IDs of those entities. Therefore `SendEmailBatchService::flagEmailsFromDigestAsSentWithSuccess` cannot identify which rows to update, and none are marked as sent.

**Required behaviour**

1. Whenever `buildSingleEmailDigest` or `buildMultipleEmailDigest` constructs a digest from one or more `email_queue` rows, the digest must store the corresponding queue IDs so that the batch service can act on them.

2. After a digest is successfully sent, all queue rows whose IDs are present in the digest must be set to `sent = true` and `locked = false`.

3. If sending fails (e.g., socket exception), the same rows must be left unsent (`sent = false`) but unlocked (`locked = false`) so they are not re-locked permanently.

4. The same handling must apply to summary digests generated when the per-recipient threshold is exceeded – all covered email IDs must be included so they are flagged as sent on success.

**Affected code areas**

- `EmailPreviewFactory::buildSingleEmailDigest` / `buildMultipleEmailDigest` – must propagate the entity IDs into the `EmailDigest` instance.
- `SendEmailBatchService::flagEmailsFromDigestAsSentWithSuccess` / `flagEmailsFromDigestAsFailedWithError` – already use `getEmailIds()` but depend on the digest being correctly populated.

**Non-obvious constraints**

- The email queue IDs must survive the transition from raw entities through digest assembly without additional persistence; the digest is an in-memory object.
- Tests that build queue entries without persisting them rely on factory helpers that must be able to assign an ID for the digest to carry. Ensure factory support for setting an ID field on an unsaved entity.

PB-28991: Fix email queue entries not marked as sent


The `generate_dummy_metadata_key` command currently creates a metadata key with `created_by` and `modified_by` set to `null`.
Change the generation logic so that both fields are populated with the ID of an existing admin user.
If no admin user is present in the database, the command must fail with a clear error message (e.g., "No admin were found in the database.") and a non-zero exit code.

PB-38031 Fixes the generate_dummy_metadata_key command


<background>
In the Passbolt API, the `AppController::error()` method renders error responses. Historically it defaulted to HTTP 200 and only overrode the response status when an explicit non‑200 code was supplied. The `AuthLoginController::loginPost()` action calls `$this->error()` for several authentication failure scenarios without supplying an explicit status code, so those failures were sent with HTTP 200.

The audit-log plugin (Passbolt/Log) records action outcomes partly based on the HTTP status code. A 200‑range response is logged as success (`status = 1`), while a 4xx/5xx response is logged as failure (`status = 0`). Because login failures returned 200, they were recorded as successful actions in the audit logs.

The browser extension (BExt) has a hard dependency on HTTP 200 for one specific partial‑success scenario: when credentials are missing in a multi‑stage GPG authentication flow. Changing that status code would break the extension.
</background>

<request>
**PB-33073: Invalid login attempts are logged as success in the audit logs**

**Problem**
When a user attempts to log in with invalid credentials, a missing identity, or a malformed GPG‑auth payload, the `AuthLoginController::loginPost()` action responds with HTTP 200 and a JSON error body. Because the HTTP status is 200, the audit‑log plugin records these failed login attempts as successful actions (`status = 1`). This makes it impossible to distinguish legitimate logins from failed ones in the audit trail.

**Expected behavior**
1. Failed login attempts must return a non‑2xx HTTP status code so the audit log correctly records them as failures (`status = 0`).
2. The audit‑log entries for the `AuthLogin.loginPost` action must show `status = 0` for any login attempt that did not fully succeed.
3. The one exception is the `FAILURE_CREDENTIALS_MISSING` result from the authentication stage—this must continue to return HTTP 200 because the browser extension relies on that status code to proceed with the multi‑stage GPG authentication flow. This specific case is a partial success from the protocol's perspective, not a hard failure.

**Scope & constraints**
- `AppController::error()` currently defaults to `200` and only changes the response status when a non‑200 code is explicitly passed. The default should be `400` instead, and the status should always be applied unconditionally.
- `AuthLoginController::loginPost()` must explicitly differentiate the failure reasons returned by the authentication result and map them to appropriate status codes:
  - `FAILURE_CREDENTIALS_MISSING` → 200 (backward compatibility with BExt)
  - `FAILURE_IDENTITY_NOT_FOUND` → 400
  - `FAILURE_CREDENTIALS_INVALID` → 400
  - `FAILURE_OTHER` → 500 (already throws `InternalErrorException`; keep as‑is)
- The change must not alter any response body structure or headers beyond the HTTP status code, except for the two cases moving from 200 to 400.
- Existing integration tests covering the auth login flow must be updated to reflect the new status codes and to assert correct audit‑log status values.
</request>

PB-33073 Fix invalid login operation should not be logged as success in the audit logs


**Bug Report: Orphaned directory relations are not cleaned up during LDAP group sync**

**Title:** PB-19040 - As AD synchronizing with LDAP, users should be removed from groups

**Observed behavior:**
When a user is removed from a group in the directory source, the corresponding `GroupsUser` (group membership) record is correctly removed during group synchronization. However, the associated `DirectoryRelation` record that links the directory entry of that user to the group is not deleted. This stale relation persists in the database and can interfere with subsequent syncs or cause data inconsistency.

The root cause is that `DirectoryRelationsTable::cleanupHardDeletedUserGroups()` fails to correctly identify `DirectoryRelation` rows that no longer have a matching `GroupsUser` record. The method relies on a query that is not effective at detecting orphans, resulting in zero deletions even when orphans exist.

**Expected behavior:**
After a user is removed from a group in the directory, the corresponding `DirectoryRelation` should be deleted during the synchronization step. The `cleanupHardDeletedUserGroups()` method should identify and remove all `DirectoryRelation` rows whose primary key (`id`) has no corresponding row in the `GroupsUsers` table. In other words, for every directory relation, there must exist a `GroupsUser` record with the same `id`; if that record is missing, the relation is orphaned and must be cleaned up.

The method should also respect the optional list of entry IDs passed to it: relations whose `parent_key` is present in that list must be left untouched (they are handled separately by the sync action).

**Impact:**
- Users who are removed from a directory group remain virtually linked to the group via orphaned relations, which may cause incorrect behavior in group membership resolution or future re-imports.
- Over time, the `directory_relations` table accumulates junk data that can complicate debugging and degrade performance.
- Group synchronization no longer reflects the true state of the directory for removed members.

**Implementation constraints:**
1. The query must find `DirectoryRelation` records where `id` does **not exist** in the `GroupsUsers` table’s primary key column (assumed to be `id`).
2. If the `$entryIds` parameter is non-empty, only relations whose `parent_key` is **not** in that list should be candidates for deletion.
3. The method must return the count of actual deletions performed.
4. No changes are required to the method’s signature or callers; only the internal query must be corrected.


Refactor SSO cookie creation to use `AbstractSecureCookieService` instead of manual `Cookie` construction with `Router::url`.

- Inject `AbstractSecureCookieService` into `AbstractSsoService` (required constructor parameter) and all Azure SSO controller actions (`stage1`, `stage1DryRun`, `triage`/`stage2`, `login`).
- Replace `clearStateCookie` and `createHttpOnlySecureCookie` in `AbstractSsoService` with calls to the injected cookie service (`createExpired` and `create`), removing the direct `new Cookie(...)` + `Router::url('/sso')` construction.
- Controllers must forward the injected service when instantiating `SsoAzureService`.
- No behavioral change: cookies must remain secure, HttpOnly, scoped to `/sso`, and retain the same expiry semantics.

PB-23920 Injects the Abstract secure cookie service in the SSO workflow


**Title:** Directory Sync v3 legacy fields mapping not updated after upgrade to v4, causing sync failures

**Description**
After upgrading a Passbolt instance from v3 to v4, the stored Directory Sync settings still contain the old v3 `fieldsMapping` structure. This causes the directory sync to use incorrect LDAP attribute names (e.g., `firstName`, `lastName`, `emailAddress` instead of the v4 equivalents), leading to failures when creating or updating users and groups.

The v4 migration (`V400ChangeLdapServersConfigKey`) reconstructed the overall configuration format but did not transform the `fieldsMapping` to the new v4 defaults. The result is that instances originally configured with v3 continue to have a broken field mapping, even if the mapping was exactly the v3 default.

**Steps to reproduce**
1. Start with an instance running v3 with a default Directory Sync configuration (AD or OpenLDAP).
2. Upgrade to v4.x (>= 4.0) and ensure the `V400ChangeLdapServersConfigKey` migration has run.
3. Observe the `organization_settings` entry with `property = 'directorySync'`.
4. Note that `fieldsMapping` still uses v3 keys (e.g., `firstName`, `lastName`, `emailAddress`, `guid`, `members`) and is not the v4 default mapping.

**Expected behavior**
During the upgrade to v4 (or in a subsequent migration), any Directory Sync configuration that was created before the v4 migration and that has the exact v3 default `fieldsMapping` should be automatically updated to the v4 default `fieldsMapping`. This ensures the directory sync continues to work without manual reconfiguration.

**Constraints & edge cases**
- Only configurations created **before** the execution of migration `V400ChangeLdapServersConfigKey` should be eligible for automatic repair. Configurations created or modified after that migration (i.e., post-upgrade) must be left untouched.
- Only the **exact v3 default** mapping (AD or OpenLDAP) can be safely migrated automatically. If an instance has any custom field mappings that diverge from the v3 default, the migration should **not** modify the settings but should instead log an error, because customized mappings cannot be blindly converted. (Manual intervention would be required in such cases.)
- The operation should be idempotent – running it multiple times must not corrupt data.
- The service must gracefully handle the absence of any Directory Sync settings in the database (no action needed).

**Impact**
Without this fix, all upgraded installations using default v3 Directory Sync will experience broken user/group synchronization. Administrators would have to manually edit the stored JSON configuration or re-run the Directory Sync setup wizard to recover.

PB-25800: Fix Directory Sync v3 legacy fields mapping in database


**Title:** Strengthen default Content-Security-Policy against clickjacking and cross-site form submission

**Context:**
The application currently sends a `Content-Security-Policy` header constructed by `ContentSecurityPolicyMiddleware`. The default policy is limited to `default-src`, `script-src`, `style-src`, `img-src`, and `frame-src`. This leaves the application unprotected against certain classes of attacks that CSP can mitigate.

**Acceptance Criteria:**

1. **Default CSP includes frame-ancestors directive**
   When no custom CSP is set via configuration (`passbolt.security.csp`), the `Content-Security-Policy` header on every response MUST include the directive:
   `frame-ancestors 'none'`
   This instructs browsers to refuse all attempts to embed the application in frames, iframes, or similar embedded contexts.

2. **Default CSP includes form-action directive**
   Under the same default conditions, the header MUST also include:
   `form-action 'self'`
   This restricts form submissions to the same origin, preventing data exfiltration to external sites.

3. **No change to existing default directives**
   The other directives already present in the default policy (`default-src 'self'`, `script-src 'self'`, `style-src 'self' 'unsafe-inline'`, `img-src 'self'`, `frame-src 'self' https://*.duosecurity.com`) remain unchanged, preserving all existing security guarantees and functionality.

4. **Custom CSP override still works**
   If a custom string is provided via the `passbolt.security.csp` configuration key, the middleware MUST emit exactly that custom string as the `Content-Security-Policy` header, without injecting the new directives. The custom configuration continues to have complete control.

5. **Header structure**
   The resulting default header MUST be a valid CSP string (semicolon-separated directives). The two new directives may appear in any order relative to the others, but they must both be present.

**Non-functional constraints:**
- No changes to the middleware’s decision to add the header only when the application is not in debug mode or when other existing conditions are met (e.g., if the response already has a CSP header or another early return condition exists, those remain unchanged).
- The implementation must not regress existing behavior for applications relying on the default or custom CSP.

PB-45158 Adds frame-ancestors:none and form-action:self to the CSP header


**PB-21551 - Subscription import fails in EE WebInstaller when an admin exists in the database but no user is in session**

**Context**
The WebInstaller for Passbolt EE includes an `importSubscription` step that requires a user identity to perform the subscription save. Currently it retrieves the user ID from the installer session (`user.user_id`), assuming the “first user” creation step has already populated it.

**Problem**
There are valid installation paths where an admin user already exists in the database (e.g., after a database restore or a partial re‑installation) but the installer session does not contain a `user.user_id`. In those cases `importSubscription` obtains `null` for the user ID, constructs a `UserAccessControl` with a null ID, and the subscription save fails with an exception or validation error. This prevents the installation from completing successfully.

**Expected behavior**
When the installer session does not contain a user ID, `importSubscription` should locate an existing admin user directly in the database (the first admin found) and use that user’s ID for the subscription import. This fallback must only be used if the session provides no user ID; normal session-based flow remains unchanged.

**Acceptance criteria**
- In the EE WebInstaller, if `user.user_id` is `null` during `importSubscription`, the system fetches the first admin user from the `Users` table and uses that ID.
- If no admin exists in the database and no user ID is in the session, the existing error handling remains in place (the call will ultimately fail as before, no silent masking).
- The subscription is successfully created/updated when an existing admin is present, even when the session lacks a user ID.
- Existing installations that rely on the session-based path are not affected.

PB-21551 - Fix subscription on Webinstaller


Create an immutable value object `EditionDto` that is the single source of truth for the application edition (`ce`/`pro`). It must:
- expose constants `EDITION_CE` and `EDITION_PRO` with the canonical literals `'ce'` and `'pro'`.
- sanitize any input string (trim, lowercase) and default to `'ce'` for anything not exactly `'ce'` or `'pro'` (so invalid, empty, or whitespace-padded values silently become Community Edition).
- provide `isCe()` / `isPro()` convenience methods.
- provide a `fromString(?string)` factory that treats `null` as `'ce'`.

Replace all direct string comparisons and the edition constant definitions inside `EditionManager` with the DTO’s constants and methods. Update `EditionManager` to use `EditionDto::EDITION_CE` for its default, `EditionDto::EDITION_PRO` in the bootstrapper mapping, and `EditionDto::EDITION_*` in `isPro()`. Update the main bootstrap and test bootstraps to check `passbolt.edition` against `EditionDto::EDITION_PRO` instead of referencing `EditionManager` constants directly. No caller should ever compare raw `'ce'`/`'pro'` strings — all edition checks must go through the DTO.

PB-51951 MEP - WP 2.4 Create the EditionDto


# Ticket: Log internal errors (500) as structured JSON with stack trace

**Context**
The `ErrorController` currently logs `InternalErrorException` by writing two separate plain-text log entries: the error message and the stack trace as a string. This makes it hard for operations tools to parse and correlate 500 errors. Additionally, other exceptions that lead to a 500 response are never logged.

**Goal**
When the application encounters any exception whose code is 500, log **one structured JSON line** containing the error message and the stack trace as an array of lines.

**Behavioral requirements**
1. **Trigger condition** – Log is written for *any* `\Exception` (or `\Throwable`) with `getCode() === 500`, not just `Cake\Http\Exception\InternalErrorException`. This ensures all 500-class errors produce a log.
2. **Log format** – The log entry must be a JSON object with the following keys:
   - `date` (ISO 8601 `DATE_ATOM`)
   - `level` (the log level string, e.g. `'error'`)
   - `message` (the exception message)
   - `trace` – an array where each element is one line of the exception’s backward trace, as obtained from `$exception->getTraceAsString()` and split by newline (`PHP_EOL`).
3. **Formatter** – Provide a dedicated `JsonTraceFormatter` under `App\Log\Formatter` that extends Cake’s `JsonFormatter`. It must recognise a context key `trace`:
   - When the `trace` context value is a *string*, overwrite the output to produce the JSON structure described above (discarding other context).
   - When `trace` is not a string or is absent, fall back to the default behaviour of the parent `JsonFormatter`.
4. **Controller integration** – Use this new formatter inside `ErrorController::beforeRender()` when logging the 500 error. The log call should pass the trace string via context using the constant `JsonTraceFormatter::TRACE` (i.e. `'trace'`).
5. **Cleanup** – Remove the now-unused `DefaultLogger` class (`src/Log/DefaultLogger.php`) that served as a thin wrapper around `Cake\Log\Log::write`.

**Non-functional constraints**
- The formatter must not break existing JSON log output for entries that lack a `trace` context.
- Splitting the trace must use `PHP_EOL` to match `Throwable::getTraceAsString()` output regardless of platform.
- The `ErrorController` changes must not affect error responses visible to API consumers; only the server-side log output changes.

PB-29437 As an admin I can log Internal errors with with the trace in Json...


The `SecretAccessesTable::createFromSecretEntity` method currently requires a `Secret` entity as its second argument. However, when a resource view includes secrets (via `contain[secret]=1`), `ResourcesViewController::_logSecretAccesses()` passes an array element from `$resource['secrets']` to this method, causing a type error. Update the method to accept both `Secret` entities and plain arrays, and use array-access notation (`$secret['resource_id']`, `$secret['id']`) so it is compatible with both types. Remove the no-longer-needed `use App\Model\Entity\Secret;` import.

PB-33852 Fixes a bug and extends code coverage


The `POST /tags/{resourceId}.json` endpoint’s controller handles too much business logic. We want to extract that logic into a dedicated service so the controller only deals with HTTP concerns (request parsing, validation, response rendering). At the same time, we want to adjust how encrypted (v5) tags are handled when the user submits a new tag list.

**Acceptance Criteria**

1. **Service separation**
   A new service class encapsulates the whole process of adding tags to a resource: patching the resource entity with new and updated tags, persisting the changes, cleaning up unused tags, and returning the final, refreshed list of tags.

2. **Controller responsibilities**
   The controller must:
   - Accept and massage the request body so that tags are always an array.
   - Validate the provided tag data (identifier format, tag existence, metadata settings compliance, etc.) before handing off to the service.
   - Call the service with the current user’s access control, the loaded resource entity, and the validated tag data.
   - Render the resulting tags using the existing metadata tags rendering service.

3. **Tag patching behavior – V4 (cleartext) tags**
   Existing access rules are preserved:
   - Only the tag owner (the `user_id` on the join record) can unlink their own personal tags.
   - Non-owners may not unlink shared tags; if they attempt to do so the request is rejected with a clear error message.
   - Tag deduplication and linking of already existing tags works as before.

4. **Tag patching behavior – V5 (encrypted metadata) tags**
   When the resource already has v5 tags and the user submits a new tag set, **any existing v5 tag is unconditionally removed** from the resource’s tag list. No ownership or shared-tag permission check is performed. The user is allowed to unlink any v5 tag they have update access to, because those tags are per-user encrypted and managed individually.

5. **Post-save cleanup**
   After the resource and join records are saved successfully, any tag that is no longer associated with any resource must be automatically deleted.

6. **Return value**
   The service must return the final list of tags associated with the resource *after* the save and cleanup operations.

7. **No other observable API changes**
   The HTTP response format, status codes, and error messages remain unchanged, with the exception of the new v5 unlinking permission relaxation.

8. **Compatibility**
   The solution must work in environments using only v4 tags, only v5 tags, and mixed setups, without regressions in existing integrations or tests.

PB-35763 Refactor resource tags add controller


**Title:** PB-46111 – Single email digest for multiple folder changes

**Background**
When several folders are created, updated, or deleted in a short period, each change currently triggers its own notification email. This quickly fills a user’s inbox with repetitive messages, especially during bulk folder operations.

**Request**
Implement an email digest that collapses all folder-related changes into a single message per recipient. The digest should be processed by the existing `passbolt email_digest send` command and follow the same batching rules already used for resource changes.

**Functional requirements**

1. **Aggregation scope**
   Aggregate emails generated by the following redactors into one digest:
   - `CreateFolderEmailRedactor`
   - `UpdateFolderEmailRedactor`
   - `DeleteFolderEmailRedactor`
   (both current and any legacy/v5 template variants that exist).

2. **Digest subject**
   - When the recipient **is** the actor: *“You made changes on several folders”*.
   - When the recipient **is not** the actor: *“{OperatorName} has made changes on several folders”*.

3. **Digest body**
   - Display the number of affected folders: *“{count} folders were affected.”*
   - Add a standard sentence that listing everything would be too long, encouraging the user to check in the application.
   - Provide a single call-to-action button linking to the relevant Passbolt page (e.g., the passwords workspace).

4. **Interaction with other digests**
   - The folder digest must be independent of the resource changes digest. If a user has both pending folder and resource changes, they may receive two separate digest emails (one for folders, one for resources), respecting each digest’s own batch logic.

5. **Integration point**
   - The digest must be registered in the `FoldersPlugin` bootstrap so it is available when the email digest sender runs.
   - Use the standard digest template abstractions (`AbstractDigestTemplate`, `DigestTemplateRegistry`) already present in the system.

**Non‑goal**
This ticket does **not** change the behaviour of individual folder emails when they are sent in isolation (i.e., when only one folder action occurs within the digest window, the existing single email remains acceptable).

**Out of scope**
- Modifying how the email digest command determines batching intervals or recipient grouping.
- Changing the content or subjects of the underlying per‑folder redactors.

PB-46111 As a user I should receive single email digest when more than one folders are created/updated/deleted


**Title:** Entity history entries missing for SecretRevisions when a secret is created or updated

**Observed Behavior**
When a user updates a resource’s secret (or creates a new secret), a new `SecretRevision` record is created in the database. The system records an `ActionLog` and writes `EntitiesHistory` rows for `Resources` and `SecretsHistory`, but no `EntitiesHistory` row is written for the `SecretRevisions` model. As a result, the audit trail has no direct link between the action log entry and the specific secret revision that was generated during that operation.

**Expected Behavior**
Every time a `SecretRevision` is created (e.g., as part of a resource secret update), an `EntitiesHistory` record should be persisted with:
- `foreign_model` set to `'SecretRevisions'`
- `foreign_key` set to the `id` of the newly created `SecretRevision`
- `crud` set to `EntityHistory::CRUD_CREATE`
This entry must be associated with the same `action_log_id` as the other entity history records from the same request.

The logging system already supports similar patterns for `Resources`, `Secrets`, and `SecretsHistory`. The `SecretRevisions` entity should be treated identically, ensuring complete audit coverage.

**Impact**
Without this entry, tools and reports that rely on `EntitiesHistory` to reconstruct which secret revision was produced by a given action cannot function correctly. Auditors cannot trace a specific secret update to the exact `SecretRevision` record, creating a gap in accountability and compliance.

**Additional Context**
- The `SecretRevisions` model has a `resource_id` and other fields; it is created via the `ResourcesUpdate` operation and possibly others.
- The fix likely involves extending the configuration in `EntitiesHistoryCreateService` and registering the necessary associations in `ActionLogsModelListener` and `EntitiesHistoryTable` so that the `EntitiesHistory` table can properly relate to `SecretRevisions`.

**Request**
Please update the entity history logging subsystem to include `SecretRevisions` creations in the audit logs, consistent with how other domain objects are recorded.

PB-46084 SH - WP3.6.7 Update action logging system to accommodate secret revisions


# Request: Verify correct log formatting for username-based action log strategy on password view and share

## Background
The `ActionLogsUsernameQueryStrategy` is responsible for formatting action log entries (into a JSON string) with human‑readable details that include the acting user’s name and the affected resource. We need to confirm that it produces the expected output for the most common operations – viewing a password and sharing a password – and that it works identically for both v4 and v5 resources.

## Acceptance criteria

1. **Password access log entry (view)**
   When a user successfully views a password (v4 or v5 resource), the written log line must be a JSON object containing at least the following keys with the specified values:
   - `user`: the username of the authenticated user performing the view
   - `action`: `"password_access"`
   - `context`: a string in the format `"{firstName} {lastName} ({username}) accessed password"` (using the authenticated user’s profile)
   - `status`: `1` (indicating success)
   - `resource_id`: the resource’s UUID
   - `resource_name`: the resource’s name
   - `resource_username`: the resource’s username
   - `resource_uri`: the resource’s URI

2. **Password share log entry (share)**
   When a user successfully shares a password (v4 or v5 resource) – i.e., adds one or more permissions – the written log line must be a JSON object containing:
   - `user`: the username of the authenticated user performing the share
   - `action`: `"share"`
   - `context`: a string that begins with `"{firstName} {lastName} ({username}) shared password with:"` followed by a space‑separated list of permission descriptions. Each description must follow the pattern `"{targetUsername} ({targetFirstName} {targetLastName}) {permissionType}"` (for user permissions) or `"group '{groupName}' {permissionType}"` (for group permissions).
   - `status`: `1`
   - `resource_id`: the resource’s UUID
   - `resource_name`: the resource’s name

3. **V4/V5 consistency**
   The same log structure must be produced regardless of whether the resource is a classic (v4) or v5 resource. There must be no difference in the presence, format, or meaning of the fields listed above.

4. **Error handling (safety constraint)**
   If the strategy cannot produce a meaningful log (for example, the action is not recognised or the user cannot be found), it must return `false` and write an error message to the application log without throwing an uncaught exception. This safety net must not interfere with the correct logging of view and share operations described above.

## Additional context
- The logging configuration will use an on‑file adapter with `ActionLogsUsernameQueryStrategy` as the strategy and a JSON formatter.
- The resource details for the view case are obtained from entity history; for the share case they come from permissions history. The final log output must correctly reflect the resource even though the retrieval paths differ.

PB-39434 Add code coverage to ActionLogsUsernameQueryStrategy


```
Title: PB-12837 Fix account recovery setup validation and service request sharing

Problem
1. The account recovery setup completion endpoint does not enforce several
   consistency rules against the organization policy, allowing invalid
   requests. Examples:
   - User rejects recovery but still sends backup keys/passwords.
   - User approves recovery but does not provide the private key or
     passwords.
   - Organization policy is mandatory but user status is rejected.
2. In several services,
   `AccountRecoveryOrganizationPolicyGetService` is instantiated with a
   `ServerRequest` object even though the service does not use it.
   This can lead to unintended request-sharing side-effects; the
   constructor should be called without the request argument where it is
   not needed.

Desired behavior
- Add validation logic to the account recovery setup completion to
  reject:
    * Any request where the policy is mandatory and the user setting is
      not “approved”.
    * Any request where the user setting is “rejected” but private key or
      password backup data is present.
    * Any request where the user setting is “approved” but the private key
      or password data is missing.
- Make policy-state checks within
  `AccountRecoveryOrganizationPolicy` more readable by introducing
  dedicated `isDisabled()` and `isMandatory()` helpers (instead of
  comparing the raw policy property against constants everywhere).
- Stop passing the `ServerRequest` to
  `AccountRecoveryOrganizationPolicyGetService` when constructing it
  inside `AbstractAccountRecoveryOrganizationPolicySetService` and
  `AccountRecoveryRecoverStartService`; just use the parameterless
  constructor.

Acceptance criteria
- Invalid account recovery setup combinations are rejected with clear
  `BadRequestException` messages.
- The affected service call-sites no longer leak a shared `ServerRequest`
  into `AccountRecoveryOrganizationPolicyGetService`.
```

PB-12837 Add tests to AccountRecoverySetupComplete and fix where request should not be shared between services


We need a dedicated, immutable value object that acts as the single source of truth for the application edition flag, replacing the ad‑hoc string constants currently scattered across the codebase.

Create an `EditionDto` in the `Passbolt\Edition\Model\Dto` namespace (inside the CE edition plugin). It must:

1. Define the canonical edition literals `ce` and `pro` as public constants.
2. Store the edition as a readonly string property, always guaranteed to be one of those two values.
3. Accept any raw string on construction, but sanitise it: trim whitespace, lower‑case, and default to `ce` if the result isn’t exactly `ce` or `pro`.
4. Provide a named constructor (`fromString`) that accepts a possibly‑null input and defaults gracefully.
5. Expose `isCe()` / `isPro()` predicates and a `getEdition()` accessor, so downstream callers never compare raw strings.
6. Provide an `toArray()` method for structured output.

After the DTO exists, update all code that currently uses `EditionManager::EDITION_CE` / `EDITION_PRO` (including `EditionManager` itself, the main and test bootstraps, solution bootstrapper tests, and any feature gate checks) to reference the new `EditionDto` constants instead. The `EditionManager` should no longer own the edition literals; it should depend on `EditionDto`.

The runtime configuration key `passbolt.edition` must stay as‑is and continue to be set to one of the `EditionDto` literals.
When loading that config, always run it through the DTO’s sanitisation to protect against malformed values.


Fix console commands exiting with a fatal type error when an entry reports an error/warning during directory sync.

- In `SyncAction::formatDirectoryData`, `get_class()` may be called on a non-object because `directory_created`/`directory_modified` can be ISO date strings or `null`. Guard the class check with an object check so that it doesn't crash when converting non-objects.
- In `GroupsCommand` and `UsersCommand` the `$this->model` property is not set before executing the sync action. Assign it to `'Groups'` and `'Users'` respectively so that error-suppression instructions (`--model=...`) are correctly constructed.

PB-42689 Fix type errors in directory_sync users & groups commands


**Title:** PB-34220 — Case‑insensitive search for folders, users and groups across all database engines

**Context**
The folders index endpoint (`/folders.json?filter[search]=…`) and the share search endpoints for users and groups (`/share/search-users/resource/{id}.json?filter[search]=…`) use a `LIKE` operator without explicit case‑folding. On database backends that perform case‑sensitive string comparison by default (e.g., PostgreSQL), a search for `"examp"` would not match a folder named `"Example"`. This leads to inconsistent behaviour depending on the underlying database engine.

**Expected behaviour**
1. **Folders search**
   - `GET /folders.json?filter[search]=term` must match folder names case‑insensitively, e.g. `"folder"` matches `"Folder"`, `"FOLDER"`, `"fOlDeR"`.
   - Partial matching (wrapping the search term with `%` before and after) must still be applied.

2. **Share search – users**
   - When searching for users to share with, the filter must match against `Users.username`, `Profiles.first_name` and `Profiles.last_name` in a case‑insensitive manner, using the same wildcard‑wrapped pattern.

3. **Share search – groups**
   - When searching for groups, the filter must match against `Groups.name` case‑insensitively.

4. **Multi‑byte and locale‑aware characters**
   - The case‑folding must correctly handle non‑ASCII characters (e.g., accented letters). The underlying database `LOWER()` function and a PHP `mb_strtolower` helper must be used in concert so that a search for `"café"` matches `"CAFÉ"` regardless of the database engine.

5. **Safety & consistency**
   - The search term must be passed as a parameterised value to prevent SQL injection.
   - The same case‑insensitive logic must be used for all three entity types (folders, users, groups), avoiding duplicate code where possible (e.g., a reusable helper trait).

**Why this matters**
Without this change, users on case‑sensitive databases cannot reliably find folders or people by partial name, creating a usability gap compared to users on case‑insensitive installs.

**Out of scope**
- Changing the default collation of database columns.
- Adjusting index strategies to accommodate the new `LOWER(…)` expressions (this may be addressed separately if performance regressions are observed).

PB-34220 As a user I can search by users and groups case insensively for all database engines


We need to add input validation for the SMTP SSL options configuration because invalid values currently cause obscure SMTP failures, making misconfiguration difficult to diagnose.

**Problem:**
The `passbolt.plugins.smtpSettings.security` configuration accepts values that are later mapped to PHP SSL context options (e.g., `sslVerifyPeer`, `sslVerifyPeerName`, `sslAllowSelfSigned` as booleans; `sslCafile` as null or a string). Currently, when `SmtpSettingsSslOptionsGetService` reads these values, there is no type validation. Administrators can inadvertently set a string for a boolean field or an array for the CA file path, and the system will attempt to use these invalid values when contacting the SMTP server. This leads to cryptic PHP warnings/errors or SMTP transport failures, with no clear indication that the issue stems from bad configuration.

**Impact:**
Debugging SMTP connectivity issues becomes unnecessarily time-consuming, especially in environments where custom SSL certificates are required. The healthcheck (`CustomSslOptionsSmtpSettingsHealthcheck`) also does not flag invalid configuration, so administrators may believe the setup is correct while the SMTP connection silently breaks.

**Expected Behavior:**

1. **Validation on retrieval** – When `SmtpSettingsSslOptionsGetService` fetches the `passbolt.plugins.smtpSettings.security` configuration, it must validate that:
   - `sslVerifyPeer`, `sslVerifyPeerName`, and `sslAllowSelfSigned` are booleans.
   - `sslCafile` is either `null` or a string.
   If any value does not match its expected type, the service should throw a `BadRequestException` with a message enumerating the specific validation errors (e.g., “The sslVerifyPeer configuration should be a boolean.”).

2. **Healthcheck integration** – The `CustomSslOptionsSmtpSettingsHealthcheck` must catch the `BadRequestException` thrown by the service. When invalid configuration is detected, the healthcheck should:
   - Mark the check as failed.
   - Report the severity level as `ERROR` (red).
   - Display a failure message clearly stating that the custom SSL configuration options are invalid (e.g., “Custom SSL configuration options set are invalid.”).

3. **Backward compatibility** – If no custom SSL options are defined (i.e., the configuration key is absent or empty), the system should continue to use the default SSL settings without validation errors. Validation should only trigger when custom values are explicitly provided.

**Additional Context:**
This improvement will make SMTP setup more robust and user-friendly by catching misconfigurations early, before they cause downstream SMTP failures. It should be implemented in the `SmtpSettingsSslOptionsGetService` and its associated healthcheck, following the existing CakePHP validation patterns used elsewhere in the project.

PB-32591 Validate passbolt.plugins.smtpSettings.security configuration values before passing it to SMTP server


**Ticket: Trim secret-history payloads while preserving audit records**

**Context**
The `SecretRevisions` plugin stores a full history of secret changes for each resource.
Currently:

- `GET /secret-revisions/resource/{id}.json` returns **all** revisions for the requesting user.
- When a new revision is saved (`SecretRevisionsTable::afterSave`), the system deletes old **revisions** (and their secrets) beyond a configured `maxRevisions` threshold.

This has two problems:

1. **Unbounded API responses** – a resource with many revisions can produce huge payloads, and most consumers only need the active revision plus a few recent ones.
2. **Loss of audit data** – deleting secret *revisions* removes the record that a change happened, which breaks compliance/audit trails. Only the encrypted payload (the *secret*) needs to be aged out.

**Settings**
The number of past revisions to retain is controlled by `SecretRevisionsSettings.maxRevisions`.
Semantically: `maxRevisions = 1` means “keep only the active revision (no history)”; `maxRevisions = N` means “keep the active revision + at most `N-1` of the most recently deleted revisions”.

**Desired behaviour**

1. **API endpoint**
   `SecretRevisionsResourceGetController::get` must:
   - Always return the active (non-deleted) revision.
   - Additionally return up to `maxRevisions - 1` deleted revisions, ordered by deletion time descending.
   - If `maxRevisions` is unset or ≤ 1, return only the active revision.
   - The endpoint must still filter by the requesting user and respect all existing `contain` options.

2. **Post-save cleanup** (`SecretRevisionsTable::afterSave`)
   - **Stop deleting secret revisions.** Every revision record (both active and deleted) must be kept indefinitely.
   - Instead, *only* trim **secrets** that belong to soft-deleted revisions.
     After saving a new revision, retain secrets for:
        - The active revision (always).
        - At most `maxRevisions - 1` of the most recently deleted revisions (if `maxRevisions > 1`).
     All other soft-deleted secrets for the same resource must be purged.
   - Secrets that are not soft-deleted (i.e. the active revision’s secrets) are never touched.
   - If `maxRevisions ≤ 1`, **all** soft-deleted secrets for the resource may be removed.

**Non‑obvious constraints**
- The “active revision” is the one where `SecretRevisions.deleted IS NULL`.
- The deletion time of a secret revision is stored in `SecretRevisions.deleted`; this column is populated only when a revision is superseded.
- The cleanup must not interfere with other resources – scope deletes by `resource_id`.
- The `_logSecretAccesses` helper should continue to work with the now-limited set of revisions returned by the controller.

**Acceptance criteria**
- Calling the endpoint with a known `maxRevisions` value returns no more than `maxRevisions` total revisions (active + past), and past revisions are the most recently deleted ones.
- After a new revision is saved, all secret revisions still exist in the database.
- Only secrets for the active revision and the required number of past revisions persist; older soft-deleted secrets are removed.
- Existing tests for access control, containment, and error conditions remain valid with the updated limits.

PB-46400 Refactors the logic to trim secret relations for simplicity