Implement the update scheduler worker and service
## Why are we doing this work
This issue covers the work that will handle the creation of the [CI/CD workload](https://gitlab.com/gitlab-org/gitlab/blob/2e7d3b21a017ab8eeb087b2e9989bd4ae8d1da72/app/services/ci/workloads/run_workload_service.rb#L13)
> [!note]
> A CI/CD workload is a new abstraction. This abstraction covers running arbitrary arbitrary workloads on the Runner infrastructure. In this case, we'll be running the dependency updates/refreshes.
This worker will generate and run a CI/CD pipeline that results in the manifests and lock files updates required to update a dependency to a patched version.
## Diagram of flow
```mermaid
%%{init: {'theme': 'dark'}}%%
graph TD
A["SBOM Ingestion Complete"] --> B["Schedule Updates Event"]
B --> C["DependencyManagement::SecurityUpdate::UpdateWorker"]
C --> D["DependencyManagement::SecurityUpdate::UpdateService"]
D --> E["Call Finder"]
E --> F["Fetch SBOM Occurrences<br/>+ Component Metadata<br/>+ Vulnerability Occurrences"]
F --> G["Filter & Order Results"]
G --> G1["Order by Severity<br/>Reachable First"]
G --> G2["Exclude Dismissed<br/>Vulnerabilities"]
G --> G3["Exclude Archived Data"]
G --> G4["Only Bundler PURL Type"]
G1 --> H["Vulnerability + Component Pairs"]
G2 --> H
G3 --> H
G4 --> H
H --> I["Check Solution for Each Pair"]
I --> J{"Solution<br/>Available?"}
J -->|No Solution| K["Filter Out Pair"]
J -->|Solution Available| L["Keep for Processing"]
K --> M["Filtered List of<br/>Dependency Updates"]
L --> M
M --> N["Group Updates<br/>by Dependency<br/>TBD"]
N --> O["Trigger CI/CD Workload<br/>for Each Component"]
O --> P["Generate & Run Pipeline"]
P --> Q["Update Manifests<br/>& Lock Files"]
style A fill:#1e3a5f,stroke:#4a9eff,color:#fff
style C fill:#5f3a1e,stroke:#ffa84a,color:#fff
style D fill:#5f3a1e,stroke:#ffa84a,color:#fff
style E fill:#3a1e5f,stroke:#b84aff,color:#fff
style J fill:#5f4a1e,stroke:#ffcc4a,color:#fff
style O fill:#1e5f3a,stroke:#4aff8a,color:#fff
style Q fill:#1e5f3a,stroke:#4aff8a,color:#fff`
```
## Relevant links
- [AI flow workload usage](https://gitlab.com/gitlab-org/gitlab/blob/2e7d3b21a017ab8eeb087b2e9989bd4ae8d1da72/ee/app/services/ai/flow_triggers/run_service.rb#L86)
- [AI Duo workflows usage](https://gitlab.com/gitlab-org/gitlab/blob/2e7d3b21a017ab8eeb087b2e9989bd4ae8d1da72/ee/app/services/ai/duo_workflows/start_workflow_service.rb#L50)
## Non-functional requirements
- [x] Documentation: We should document the priority we give to our updates publicly.
- [x] Feature flag: The worker and service should respect the FF.
- [x] Performance: The finder should run with a p95 of 500ms
- [x] Testing: We need to test that we deterministically order (and potentially group) the dependency updates.
## Implementation plan
### MR 1: Create a finder for the vulnerabilities
We'll need to create a finder that fetches the SBOM occurrences, their
SBOM component metadata (purl type, version, etc.) and the associated
SBOM vulnerability occurrences.
- Vulnerability occurrences should return ordered from most severe to least severe.
- Vulnerability order should also take into account reachable components first.
- Vulnerability results should omit vulnerabilities that have been dismissed.
- Archived data (projects, vulnerabilities, sbom occurrences) should be excluded.
- We should only get for vulnerabilities that are associated with supported PURL types - **only Bundler is supported at this stage**!
### MR 2: Create a security update worker and service
The `DependencyManagement::SecurityUpdate::UpdateWorker` worker will call the `DependencyManagement::SecurityUpdate::UpdateService` to start the process of launching new pipelines that update the dependencies.
- The service calls the finder
- It checks the solution for each of the vulnerability + component pairs.
- If the solution matches a known "no solution is available" description, the pair is omitted/filtered out.
- If the solution doesn't match then we assume that there's a solution available, and keep it for further processing.
- TBD: Group dependency updates for the same dependency.
- Finally we take the list and trigger a CI/CD workload to update each of the components remaining.
- TBD: Should we create a separate event for this? The event chain would look like this: `(sbom ingestion done) -> (schedule updates) -> (schedule individual update)`.
## Verification steps
Verify that the event is emitted when a supported dependency update (Bundler update) is run and the feature flag is toggled on.
issue