Skip to content

Implement stale indicator for secrets

Related: #571232

What does this MR do and why?

This MR introduces a stale status indicator for project secrets using lifecycle timestamps (create_started_at, create_completed_at, update_started_at, update_completed_at). The system now derives a status field exposed via GraphQL to identify whether a secret is completed or stale.

Status logic

Status Description
COMPLETED Secret was recently created or updated, or no timestamps are present.
UPDATE_STALE Secret is potentially outdated, stuck, or has invalid/missing timestamps (e.g. update started long ago without completion).
CREATE_STALE Secret creation appears stale or invalid, possibly due to missing timestamps or a create operation that started long ago without completion.

Purpose

  • Enables frontend/API consumers to detect stale secrets.

  • Lays the foundation for future features such as automatic cleanup or deletion of stale secrets.

Timestamp logic:

Timestamp Field Purpose
create_started_at Marks when secret creation began.
create_completed_at Marks when creation finished successfully.
update_started_at Marks when a rotation/update was initiated.
update_completed_at Marks when the update was confirmed complete.

These timestamps allow the system to infer the health of a secret:

  • Valid / Completed State

    • Creation or update completed normally (start < finish, and finish is recent).

    • No timestamps present is treated as safe/default (completed).

  • ⚠️ Stale / Invalid State

    • An operation started but did not complete within a defined threshold.

    • Timestamps are reversed (completion before start → indicates failed or interrupted process).

    • Missing completion timestamp after significant time implies secret may be stuck or abandoned.

References

Screenshots or screen recordings

Before After
Screenshot_2025-10-21_at_00.33.41 image

How to set up and validate locally

How to set up and validate locally

  1. Start OpenBao in your GDK:
   gdk openbao start
  1. Ensure your GDK is up to date and restart:
   gdk update
   gdk restart
  1. Enable the secrets management feature flag in Rails console:
   Feature.enable(:secrets_management)
  1. Navigate to your test project in the browser:
   http://127.0.0.1:3000/your-namespace/your-project
  1. Enroll the project in secrets management via the UI:

    • Go to Settings > CI/CD
    • Expand the Secrets Management section
    • Click Enable Secrets Management (or similar enrollment button)
    • Complete the enrollment process
  2. Navigate to the secrets management interface and create a new secret:

    • Go to Settings > Secrets (or wherever secrets are managed in the UI)
    • Click Create secret
    • Fill in the form:
      • Name: TEST_SECRET
      • Value: test-value
      • Description: Test secret for status validation
      • Environment: production
      • Branch: main
    • Click Create secret
  3. Verify via GraphQL API (optional):

   query {
     project(fullPath: "your-namespace/your-project") {
       projectSecret(name: "TEST_SECRET") {
         name
         status
         metadataVersion
       }
     }
   }
  1. Run the test suite to ensure all tests pass:
   bundle exec rspec ee/spec/models/secrets_management/project_secret_spec.rb
   bundle exec rspec ee/spec/services/secrets_management/project_secrets/
   bundle exec rspec ee/spec/requests/api/graphql/secrets_management/project_secrets/

Expected behavior

  • Newly created secrets show status: "COMPLETED" and metadataVersion: 2
  • Updated secrets increment metadata version by 1 and maintain status: "completed"
  • Timestamps (create_started_at, create_completed_at, update_started_at, update_completed_at) are tracked in the secret metadata
  • Status changes to "UPDATE_STALE" or "CREATE_STALE" if operations take longer than 30 seconds without completion (edge case)

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.

Edited by Dmytro Biryukov

Merge request reports

Loading