Create/Update/Delete Group Secrets

Feature

Full CRUD operations for group secrets

This implements Exclusive Lease for Group Secret Operations as initially captured by #577347 (closed).

Scope

  • GroupSecret model with validations (name, description, protected, environment)
  • CreateService - validates, stores secret in OpenBao, handles rotation info, adds to policy
  • UpdateService - handles value, description, protected flag, and environment changes with policy transitions
  • DeleteService - removes secret from OpenBao and policies
  • SecretRefresher - handles adding/removing secret paths from policies, manages environment and protected flag combinations
  • Handle policy transitions when protected flag or environment changes
  • Support for wildcard environments (e.g., staging-*)
  • Support metadata CAS for optimistic locking
  • Clean up rotation info on delete
  • Implement stale indicator mechanism - add timestamp tracking (create_started_at, create_completed_at, update_started_at, update_completed_at) in custom metadata to detect partially failed operations
  • Expose stale boolean in GraphQL responses to indicate secrets needing attention
  • GraphQL mutations: groupSecretCreate, groupSecretUpdate, groupSecretDelete
  • GraphQL types: GroupSecretType with stale field

Implementation table

frontend Frontend: Create and update group secrets (#577464)
frontend Frontend: Delete group secrets (#577480)

Can be split into separate MRs

  • MR 1: Create mutation (model, CreateService, SecretRefresher, GraphQL mutation, stale tracking)
  • MR 2: Update mutation (UpdateService with policy transitions, GraphQL mutation)
  • MR 3: Delete mutation (DeleteService, GraphQL mutation)

Deliverable

Users can create, update, and delete group secrets via GraphQL, with visibility into partially failed operations

Dependencies

#577341 - Update/Delete Group Secret Permissions

Notes

Policy Structure

Group secrets support environment scoping combined with protected flag, creating policies for each combination:

Literal environment + protected combinations:

  • pipelines/protected/env/{env_hex} - specific environment, protected branches only
  • pipelines/unprotected/env/{env_hex} - specific environment, any branch
  • pipelines/protected/global - any environment (*), protected branches only
  • pipelines/unprotected/global - any environment (*), any branch

Wildcard environment support:

  • Environment patterns like staging-* are supported
  • Requires glob policy templates in JWT role
  • Similar to project secrets wildcard handling

Policy Management

The SecretRefresher handles:

  • Create: Add secret path to policy matching (environment, protected) combination
  • Update: Move secret path between policies when environment or protected changes
  • Delete: Remove secret path from policy
  • JWT role updates: Add/remove glob policy templates when wildcard environments are used

Differences from Project Secrets

  • ✅ No branch scoping (only environment + protected flag)
  • ✅ No combined environment+branch policies
  • ✅ Simpler policy naming (no branch hex encoding)
  • ❌ Still has environment wildcards and glob policies (same complexity as project secrets for this part)

Secret Storage

  • Secrets stored at secrets/kv/data/explicit/{name}
  • Metadata includes: environment, protected, description, secret_rotation_info_id

Stale Tracking

  • Uses timestamps to detect if create/update operations didn't complete (see #571232#note_2810300079)
  • Stale secrets shown in UI with option to delete and recreate
  • No automated repair - users must manually recreate stale secrets
Edited Jan 08, 2026 by Fabien Catteau
Assignee Loading
Time tracking Loading