Repository navigation
Implement org-owned service accounts with space entitlements and workload identity #5520
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
rkoster
wants to merge
200
commits into
cloudfoundry:main
Choose a base branch
from
rkoster:service-accounts-poc
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
200 commits
Select commit
Hold shift + click to select a range
a0501f5
Test space-owned service accounts and same-space assignment (red)
rkoster 6d14ea8
Implement space-owned service accounts and same-space assignment
rkoster d7d6353
Test same-space app account relationship endpoint (red)
rkoster 668c4f0
Expose same-space app service account relationship
rkoster 9008ffd
Test account client and OAuth principal provisioning (red)
rkoster d78294c
Reconcile account clients and roleless OAuth principals
rkoster c8a5c2d
Test provisioning HTTP retries and altered TLS policies (red)
rkoster 6aa4ca0
Normalize managed client sets and reject extra TLS policies
rkoster 91fff36
Test retryable account provisioning worker job (red)
rkoster 4428266
Add credential-free retryable account provisioning job
rkoster 1f22e71
Test configured provisioning client and token refresh (red)
rkoster ed54722
Configure dedicated account provisioning client in workers
rkoster 36d439c
Test asynchronous first-bind provisioning and job reuse (red)
rkoster 0bc48a6
Queue pollable provisioning on authorized first bind
rkoster 9c4a101
Test account listing description and metadata updates (red)
rkoster 98dbf8d
Add scoped account listing description and metadata APIs
rkoster fee96b0
Test account disable enable and safe deletion lifecycle (red)
rkoster 19167e5
Reconcile account disable enable and unused-account deletion
rkoster 88182e4
Test service account and assignment audit events (red)
rkoster 01a0cf9
Audit service account lifecycle and assignment changes
rkoster 6698b22
Test explicit account roles without human UAA lookup (red)
rkoster 3e1e289
Resolve managed account names locally for explicit role APIs
rkoster c885c1f
Test typed runtime identity and fail-closed account gates (red)
rkoster 8554429
Build typed ready-account runtime identity and discovery metadata
rkoster 9b190e0
Test runtime and task account propagation boundaries (red)
rkoster ae7c301
Propagate account identity to runtime recipes and discovery
rkoster ce5df05
Test task account identity snapshot at creation (red)
rkoster 9b74065
Snapshot task account identity before asynchronous submission
rkoster d103ed9
Test process account launch snapshot on restart (red)
rkoster 3e3a3d6
Preserve process account launch identity until explicit restart
rkoster 37b08b8
Test staging exclusion of injected account discovery (red)
rkoster f9c0c9d
Exclude service account discovery from all staging inputs
rkoster 9396e4f
Test active identity deletion and secretless discovery guards (red)
rkoster 2773e73
Protect active launch identities and non-secret endpoint discovery
rkoster db812b5
Verify pollable account provisioning retries through completion
rkoster 48d64c8
Verify concurrent apps share one first-bind provisioning job
rkoster bd5c54d
Test provisioning validation for API local workers (red)
rkoster 201ab95
Validate optional provisioning inputs for API local workers
rkoster b576bf8
Test pre-feature launches cannot acquire new account identity (red)
rkoster 2198d8c
Keep pre-feature launches account-free until explicit launch
rkoster 46eb624
Test account app listing applies requested filters (red)
rkoster 9bc0cc1
Apply normal app filters to account app listing
rkoster e4bf7ac
Test bind exclusion during retrying lifecycle operations (red)
rkoster b4cea54
Block binding during retrying disable or delete operations
rkoster 1726f83
Test owned account guard before recursive space deletion (red)
rkoster 817c5a6
Report owned service accounts before recursive space deletion
rkoster 19adbae
Verify rebuilt LRPs preserve launch account after unbind
rkoster 4bccc9b
Document experimental space-owned service account API and rollout
rkoster f014a3b
Test MySQL account relationship collation on migration retry (red)
rkoster f7786f5
Match parent MySQL collation and retry partial account assignment mig…
rkoster 7a16b72
Test UAA normalized inert scope during account reconciliation (red)
rkoster d972bc3
Accept UAA inert scope normalization for managed client reconciliation
rkoster b6a3634
Test rolling service account creation budget and admin exemption (red)
rkoster 9fe3e79
Enforce atomic weekly service account creation budget for non-admins
rkoster 9642e1c
Test cascading account cleanup on space and org deletion (red)
rkoster 1943c86
Correct task fixture and confirm assigned workload cascade failure (red)
rkoster fa942e9
Cascade owned service account cleanup during space and org deletion
rkoster ae39ff0
Test registering account clients by UAA trust bundle reference (red)
rkoster dc0ce61
Register account clients by UAA trust bundle reference when configured
rkoster 5074283
Test reconciling trust-anchor drift on owned account clients (red)
rkoster 3958f06
Update owned account clients on trust-anchor drift instead of rejecti…
rkoster e059a98
Test updating owned account clients through the management client (red)
rkoster 6a0864e
Expose client updates on the service account management client
rkoster d962886
Test requiring UAA trust bundle references for account clients (red)
rkoster 47c6bd5
Require UAA trust bundle references for account clients and drop inli…
rkoster a4247e6
Test immutable organization service account prefix allocation (red)
rkoster d54e075
Allocate immutable organization service account prefixes
rkoster 8299885
Test account organization ownership and initial space entitlement (red)
rkoster c7de546
Persist account organization owners and initial space entitlements
rkoster 6581773
Test retaining org accounts across space deletion (red)
rkoster 8d68274
Retain service accounts on space deletion and clean up with their org
rkoster a446b3c
Test account space entitlement APIs and developer permissions (red)
rkoster cc5efc5
Authorize account use and management through org space entitlements
rkoster d121064
Test qualified org-local account names and explicit tombstone reuse (…
rkoster 637527f
Scope account identities and tombstones to immutable org namespaces
rkoster c9016a0
Test org account quota API and capacity enforcement (red)
rkoster e46228c
Enforce organization service account capacity quotas
rkoster 3a7a37b
Test bearer account registration with required org attribution (red)
rkoster 08845a5
Register bearer account clients with owning org and workload attribution
rkoster 3bde1d3
Test prefix-qualified runtime identity across entitled spaces (red)
rkoster 3cdf836
Send qualified account identity for apps in entitled spaces
rkoster 7bcd1a4
Test platform service account context on broker app bindings (red)
rkoster 20efc9b
Correct broker context fixture and confirm missing identity context (…
rkoster 047ca8f
Include platform-controlled account identity in broker binding context
rkoster 76275d8
Test qualified service account route sources and grant cleanup (red)
rkoster 6a86ce7
Resolve qualified account route sources and remove their grants on de…
rkoster f4d20d2
Test account reassignment guard for broker bindings (red)
rkoster 30b6a5f
Block account reassignment while broker bindings remain
rkoster 5055bb1
Test prefix and writable-space entitlement authorization guards (red)
rkoster c999e95
Require allocated prefixes and active developer spaces for account ma…
rkoster e4042d0
Test readable account route sources and qualified filtering (red)
rkoster a44abb9
Authorize account route grants and support qualified source filters
rkoster 6fe38b1
Test qualified runtime contract gate fails closed by default (red)
rkoster 25292b7
Gate qualified runtime identities on explicit contract version two
rkoster 8fdaf64
Test durable deletion history across explicit account name reuse (red)
rkoster 2be0f15
Retain account deletion timestamps independently of reusable reservat…
rkoster 7498075
Test qualified route account rules require an enforcing router contra…
rkoster db39623
Gate service account route rules on qualified router support
rkoster d02758d
Test concurrent account quota enforcement in the registry (red)
rkoster cd03ff6
Serialize registry quota checks under the owning organization lock
rkoster 6f3060e
Test rejecting new assignments without an organization prefix (red)
rkoster e89fc24
Require allocated organization prefixes for new account assignments
rkoster 471ca8e
Test named UAA resource policy registration (red)
rkoster 04947ab
Register operator named UAA resource policies when configured
rkoster 5ea1178
Test rejecting new entitlements during account deletion (red)
rkoster 513191d
Reject entitlement additions once account deletion begins
rkoster d80a64b
Test account relationships and included sources on route policies (red)
rkoster b2f04d9
Present readable account relationships and included route sources
rkoster d06c5c8
Test safe rollback of an empty account namespace transition (red)
rkoster 0914c0e
Allow empty namespace rollback while rejecting lossy identity downgrades
rkoster 78fae23
Test same-org enforcement on direct entitlement association writes (red)
rkoster 9e0dfcd
Validate same-organization ownership for every space entitlement
rkoster 044330d
Test rechecking account management rights under the account lock (red)
rkoster 0b452e7
Recheck account lifecycle authorization after locking current entitle…
rkoster c700b7d
Test legacy unqualified identities retain global collision protection…
rkoster 37d9ad8
Preserve global collision reservations for retiring unqualified ident…
rkoster 60fe0f5
Test preserving pre-identity broker binding semantics (red)
rkoster 496080a
Snapshot account identity on service bindings and retain legacy bindi…
rkoster c6d854d
Test identity-bearing bindings protect account lifecycle references (…
rkoster 3837232
Protect account deletion and entitlement revocation with binding refe…
rkoster e049719
Test binding snapshots revalidate account entitlement at persistence …
rkoster aea3efb
Lock app and account before capturing broker binding identity
rkoster 159287d
Test launch snapshot rechecks the account space entitlement (red)
rkoster 49165a4
Lock and revalidate account entitlement before process launch snapshots
rkoster b724da3
Test task launch serializes account entitlement validation (red)
rkoster a358230
Lock account entitlement when creating runtime task snapshots
rkoster 35a434e
Test broker binding fails closed for a missing captured account (red)
rkoster f1c001d
Refuse broker requests when a captured account identity is missing
rkoster 60a8b9a
Test rejecting entitlements to deleting spaces (red)
rkoster 7f056fb
Reject granting account entitlements to deleting spaces
rkoster 3c7b0de
Test failed org account cleanup leaves a deleting parent (red)
rkoster 8549600
Mark orgs deleting before retryable service account cleanup
rkoster 0fe6772
Test reservation deletion counts and age observability (red)
rkoster 7f93c66
Expose account reservation counts and deletion age statistics
rkoster 6dd9039
Test reservation observability uses the organization namespace (red)
rkoster 9a1c688
Scope unknown reservation age statistics to organization and name
rkoster 6e75d80
Test rejecting route grants while account deletion is active (red)
rkoster 6a11a0e
Serialize account route grants against account deletion
rkoster bc73646
Test revocation response after the caller loses account visibility (red)
rkoster c1bc21a
Return successful entitlement revocation without reauthorizing the re…
rkoster a5ed905
Test account name reuse warnings and prior identity audit linkage (red)
rkoster 1b5bbca
Warn on account name reuse and link the prior identity in audit history
rkoster eb18c0b
Read prior account deletion from the timestamped history row
rkoster f6c9262
Test account creation rechecks deleting org after locking (red)
rkoster 60f7001
Reject new accounts when org deletion wins the organization lock
rkoster b5c0dfa
Test role management for qualified account principals (red)
rkoster 73d6b88
Resolve qualified account principals without human UAA username lookup
rkoster de04b44
Test shared-domain safeguards remain during org account cleanup (red)
rkoster 1213f2f
Check shared domains before marking account-owning organizations dele…
rkoster 9b4e7b6
Refresh owned domains when guarding account cleanup and preserve exis…
rkoster ead0dd1
Document org-owned account APIs and align acceptance fixtures
rkoster a98f8a0
Cover quota lowering with cached organization associations
rkoster 7713454
Test suspended source spaces cannot authorize entitlement expansion (…
rkoster 52068ab
Require current active source entitlements for developer sharing
rkoster fd9af84
Test account route policies need no router-version setting (red)
rkoster f9d5880
Remove router contract gate and require routing-first release sequencing
rkoster ba95284
Align regression expectations with account prefixes and entitlements
rkoster 98bab7d
Test concurrent account provisioning after permission snapshots (red)
rkoster 3c52afd
Use current locking read when reusing account provisioning jobs
rkoster 949f62e
Test MySQL budget snapshots and namespace rollback indexes (red)
rkoster ef91b92
Test full empty account-assignment rollback on MySQL (red)
rkoster 498d40b
Fix MySQL account creation snapshots and rollback index dependencies
rkoster 7f69c1d
Test account assignment after concurrent entitlement revocation (red)
rkoster 436df9d
Read current space entitlement after locking account for assignment
rkoster f285ecc
Test independent CAPI user lifecycle for service accounts (red)
rkoster 4eaaf6d
Decouple CAPI users and roles from service account lifecycle
rkoster 25923ee
Test org cleanup of unprovisioned account reservations (red)
rkoster f9f707f
Clean unused account reservations without UAA provisioning dependency
rkoster a21dd5e
Remove unpublished POC compatibility and reservation statistics
rkoster 14427ac
Test model-owned lookup of qualified account client IDs (red)
rkoster 1b10bdf
Resolve qualified client identities through service account model
rkoster 3b42219
Test bounded association queries for service account lists (red)
rkoster ac242dc
Eager load associations for service account list presentation
rkoster e0bf2ab
Test entitlement revocation in nonwritable spaces (red)
rkoster 523bcac
Require writable spaces for account entitlement revocation
rkoster 1032d9f
Test account-keyed lifecycle reference indexes and rollback (red)
rkoster 32fef5c
Index service account references for lifecycle checks
rkoster aadbdba
Test user-provided bindings remain independent of account identity (red)
rkoster 8b7dfb6
Capture account identity only for managed service bindings
rkoster a33e5a4
Test V2 broker binding identity before persistence (red)
rkoster 7c99596
Capture and lock V2 service account identity before broker bind
rkoster 0729130
Test recovery of partially applied app account migration (red)
rkoster 9ddfe25
Resume app account migration after foreign key or index interruption
rkoster 27fe3ee
Preserve V2 orphan cleanup jobs and fix list spec formatting
rkoster 50a88d6
Test invalid concurrent account reference index recovery (red)
rkoster a47a5cb
Repair invalid PostgreSQL service account reference indexes on retry
rkoster 648f47d
Test recursive V2 org service account cleanup and retry (red)
rkoster 7dc3652
Share retryable service account cleanup with V2 org deletion
rkoster 9f69c86
Test single service account activation and updater worker restart (red)
rkoster 12534ae
Use one service account enable setting across CAPI processes
rkoster a5eb5e9
Test disabled account reconciliation preserves shared domain freshnes…
rkoster a35d32b
Pin enabled runtime config in disabled account sync regression (red)
rkoster 405a062
Keep process sync freshness on expected account readiness rejection
rkoster 0aa5d10
Test accepted GUID and timestamp filters on service account lists (red)
rkoster 1bf0e29
Apply common GUID and date filters to service account lists
rkoster 58a04f1
Test space-first entitlement lookup index (red)
rkoster f2903b3
Index entitlement lookups by space and account
rkoster 2f0f042
Test shared issuer discovery reuse expiry and failure handling (red)
rkoster e4a087a
Share synchronized UAA issuer discovery across broker binds
rkoster 864cb3b
Parse issuer discovery strictly and fix concurrent spec formatting
rkoster File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| require 'repositories/service_account_event_repository' | ||
|
|
||
| module VCAP::CloudController | ||
| class AppAssignServiceAccount | ||
| class Error < StandardError; end | ||
| class Unauthorized < Error; end | ||
| class Conflict < Error; end | ||
|
|
||
| def initialize(permissions, actor: nil) | ||
| @permissions = permissions | ||
| @actor = actor | ||
| end | ||
|
|
||
| def assign(app, account, provision: false) | ||
| job = nil | ||
| app.db.transaction do | ||
| app.lock! | ||
| raise Unauthorized.new('not authorized to update the app') unless @permissions.can_write_to_active_space?(app.space.id) | ||
|
|
||
| validate_binding_change!(app, account) | ||
|
|
||
| if account | ||
| account.lock! | ||
| raise Conflict.new('organization service account prefix is unset') unless account.organization.service_account_prefix | ||
| raise Conflict.new('account must be entitled to the app space in the same organization') unless currently_entitled?(account, app.space) | ||
|
|
||
| validate_ready!(account, provision) | ||
| raise Conflict.new('another service account is already assigned; unbind first') if app.service_account_guid && app.service_account_guid != account.guid | ||
|
|
||
| job = provision_account(account) unless account.status == 'ready' | ||
| end | ||
|
|
||
| unless app.service_account_guid == account&.guid | ||
| previous_guid = app.service_account_guid | ||
| app.update(service_account: account) | ||
| record_assignment(app, account, previous_guid) if @actor | ||
| end | ||
| end | ||
| provision ? job : app | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def currently_entitled?(account, space) | ||
| account.organization_id == space.organization_id && account.db[:service_account_space_entitlements]. | ||
| where(service_account_guid: account.guid, space_guid: space.guid).for_update.first | ||
| end | ||
|
|
||
| def validate_binding_change!(app, account) | ||
| return unless app.service_account_guid && app.service_account_guid != account&.guid && app.service_bindings_dataset.exclude(service_account_guid: nil).any? | ||
|
|
||
| raise Conflict.new('remove service bindings before changing the service account') | ||
| end | ||
|
|
||
| def record_assignment(app, account, previous_guid) | ||
| Repositories::ServiceAccountEventRepository.record( | ||
| app, account ? 'assign' : 'unassign', @actor, | ||
| service_account_guid: account&.guid || previous_guid | ||
| ) | ||
| end | ||
|
|
||
| def validate_ready!(account, provision) | ||
| raise Conflict.new('service account is not ready or enabled') unless account.enabled && (account.status == 'ready' || provision) | ||
|
|
||
| if PollableJobModel.where(resource_guid: account.guid, resource_type: 'service_account', state: %w[PROCESSING POLLING]).exclude(operation: 'service_account.provision').any? | ||
| raise Conflict.new('service account lifecycle operation is in progress') | ||
| end | ||
| end | ||
|
|
||
| def provision_account(account) | ||
| job = PollableJobModel.where(resource_guid: account.guid, operation: 'service_account.provision', state: %w[PROCESSING POLLING]).for_update.first | ||
| return job if job | ||
|
|
||
| account.update(status: 'reconciling') | ||
| Jobs::Enqueuer.new(queue: Jobs::Queues.generic).enqueue_pollable(Jobs::V3::ServiceAccountProvision.new(account.guid)) | ||
| end | ||
| end | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| require 'actions/service_account_provision' | ||
| require 'repositories/service_account_event_repository' | ||
|
|
||
| module VCAP::CloudController | ||
| module OrganizationServiceAccountCleanup | ||
| private | ||
|
|
||
| def shared_domain_errors(org) | ||
| return [] unless ServiceAccountModel.where(organization_id: org.id).any? | ||
|
|
||
| domains = org.owned_private_domains_dataset.all.select(&:shared_with_any_orgs?) | ||
| return [] if domains.empty? | ||
|
|
||
| details = domains.map { |domain| "Domain '#{domain.name}' is shared with other organizations. Unshare before deleting." }.join("\n") | ||
| [CloudController::Errors::ApiError.new_from_details('OrganizationDeletionFailed', org.name, details)] | ||
| end | ||
|
|
||
| def mark_deleting_for_account_cleanup(org) | ||
| return unless ServiceAccountModel.where(organization_id: org.id).any? | ||
|
|
||
| org.db.transaction do | ||
| org.lock! | ||
| org.update(status: Organization::DELETING) | ||
| end | ||
| end | ||
|
|
||
| def delete_service_accounts(org) | ||
| accounts = ServiceAccountModel.where(organization_id: org.id).order(:guid).all | ||
| return [] if accounts.empty? | ||
|
|
||
| accounts.each_with_object([]) do |account, errors| | ||
| locally_deleted = false | ||
| account.db.transaction do | ||
| account.lock! | ||
| if PollableJobModel.where(resource_guid: account.guid, resource_type: 'service_account', state: %w[PROCESSING POLLING]).any? | ||
| raise ServiceAccountProvision::Conflict.new('service account operation is already in progress') | ||
| end | ||
|
|
||
| if account.status == 'reserved' && !account.in_use? | ||
| Repositories::ServiceAccountEventRepository.record(account, 'delete', @user_audit_info, { recursive: true }) | ||
| account.destroy | ||
| locally_deleted = true | ||
| else | ||
| account.update(enabled: false, status: 'deleting') | ||
| end | ||
| end | ||
| next if locally_deleted | ||
|
|
||
| Repositories::ServiceAccountEventRepository.record(account, 'delete', @user_audit_info, { recursive: true }) | ||
| CloudController::DependencyLocator.instance.service_account_provisioner.deprovision(account, delete: true) | ||
| rescue StandardError => e | ||
| errors << e | ||
| end | ||
| end | ||
| end | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| module VCAP::CloudController | ||
| class ServiceAccountCreationBudget | ||
| WINDOW = 7.days | ||
|
|
||
| def self.consume(principal, exempt:) | ||
| return yield if exempt | ||
|
|
||
| # Lock the authenticated principal, not a space: requests on different API | ||
| # instances and in different spaces must share one atomic budget. | ||
| principal.lock! | ||
| now = Time.now.utc | ||
| creations = ServiceAccountModel.db[:service_account_creations] | ||
| limit = Config.config.get(:service_account_creation_limit) || -1 | ||
| # MySQL permission/authentication reads may have established an older | ||
| # repeatable-read snapshot before the principal lock was acquired. | ||
| used = creations.where(principal_guid: principal.guid).where { created_at > now - WINDOW }.select(:principal_guid).for_update.all.size | ||
| raise CloudController::Errors::V3::ApiError.new_from_details('ServiceAccountCreationLimitExceeded') if limit.between?(0, used) | ||
|
|
||
| result = yield | ||
| # Independent of accounts, tombstones and audit-event retention. Failed | ||
| # creations roll this back; successful deletions never refund the budget. | ||
| creations.insert(principal_guid: principal.guid, created_at: now) # rubocop:disable Rails/SkipsModelValidations -- Transactional creation ledger, not an ActiveRecord model. | ||
| creations.where(principal_guid: principal.guid).where { created_at <= now - WINDOW }.delete | ||
| result | ||
| end | ||
| end | ||
| end |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.