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
-
GroupSecretmodel 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
protectedflag orenvironmentchanges - 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
staleboolean in GraphQL responses to indicate secrets needing attention - GraphQL mutations:
groupSecretCreate,groupSecretUpdate,groupSecretDelete - GraphQL types:
GroupSecretTypewithstalefield
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
environmentorprotectedchanges - 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 by Fabien Catteau