Geo - Replicate Vulnerabilities::Remediation uploads

What does this MR do and why?

Add Geo SSF (self-service framework) replication and verification for the vulnerability_remediation_uploads partition table (Vulnerabilities::Remediation model), so vulnerability remediation attachments are mirrored from the primary to secondary Geo sites alongside other upload types.

Generated with scripts/geo/generate-blob-replicator and adjusted for Vulnerabilities::Remediation specifics:

  • Shorten Postgres identifiers (vuln alias for vulnerability) on the registry FK unique index and the state table indexes so they fit the 63-character limit.
  • The geo_vulnerability_remediation_upload factory deletes the Upload auto-created by the Vulnerabilities::Remediation parent factory (which mounts a file via AttachmentUploader) before creating the controlled :with_file fixture, so only one row lands in the partition. This mirrors the issuable_metric_image_upload factory.

Selective sync uses the project_id sharding key directly via the parent factory's project: keyword.

Replication is gated by the ops feature flag geo_vulnerability_remediation_upload_replication (default disabled); flipping it on for general availability is tracked separately under the parent epic.

Changelog: added EE: true

References

How to set up and validate locally

Validation requires a local Geo setup (primary + secondary), and make sure you run geo migrations with: rails db:migrate:geo. Then:

  1. On the primary, enable the feature flag:

    Feature.enable(:geo_vulnerability_remediation_upload_replication)
  2. Create a Vulnerabilities::Remediation with an attached file. There is no simple UI flow for this (remediations are created during security report ingestion), so create one in the Rails console on the primary:

    project = Project.first
    path = Rails.root.join('ee/spec/fixtures/vulnerabilities/remediation_patch.b64')
    
    remediation = Vulnerabilities::Remediation.new(
      project: project,
      summary: 'Test remediation for Geo replication',
      checksum: Digest::SHA256.hexdigest(File.read(path))
    )
    remediation.file = File.open(path)
    remediation.save!
    
    # The mounted AttachmentUploader writes an Upload routed to the
    # vulnerability_remediation_uploads partition. Confirm it landed:
    Geo::VulnerabilityRemediationUpload.where(model_id: remediation.id).last
  3. On the secondary, watch the registry get populated:

    Geo::VulnerabilityRemediationUploadRegistry.last

    Confirm it transitions through pending → started → synced and that verification_state reaches succeeded.

  4. Confirm the file exists on the secondary's object storage / disk at the same path as the primary.

  5. Spot-check the GraphQL API:

    {
      geoNode(name: "<secondary-name>") {
        vulnerabilityRemediationUploadRegistries { nodes { id state } }
      }
    }

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Merge request reports

Loading