Class GrantRequestService
GrantRequest state transition (SPEC items 3 and 8).
No other class may change a grant request's status.
Concurrency (D-20 discipline, same as RunRequestService): every
load→validate→transition→persist sequence runs under one ReentrantLock, which makes
each transition an effective compare-and-set together with the store's atomic rewrite.
Approval creates and registers the Grant inside the same critical section, so a
request can never yield two grants.
Failure families: IllegalArgumentException for input validation,
IllegalStateException for wrong-state transitions, AccessDeniedException
(403 on the web layer) for authorization refusals.
S-15: create(io.jenkins.plugins.batchcontrol.model.GrantScope, java.util.List<io.jenkins.plugins.batchcontrol.model.GrantAction>, int, java.lang.String, java.lang.String) and approve(java.lang.String, java.lang.String) refuse outright while change control is off,
because the switch is a kill switch and a window approved while it is off would otherwise take
effect unreviewed the moment it was turned back on. See checkChangeControlEnabled.
-
Method Summary
Modifier and TypeMethodDescriptionApproves a PENDING grant request and creates the grant.Cancels a PENDING grant request; requester or a Manage holder only (SPEC item 7 rule).changeApprovers(String id, List<String> newApprovers) Replaces the designated approver set of a PENDING grant request; requester only (SPEC item 3 rules reused, D-26, D-37).countPendingFor(org.springframework.security.core.Authentication auth) D-61: the PENDING grant requests that concernauth, read from the open-request index only (no history scan): those awaiting their decision as a designated approver holding Jenkins-levelBatchControl/Approve, else their own.create(GrantScope scope, List<GrantAction> actions, int durationMinutes, String reason, String approver) Creates a PENDING grant request.create(GrantScope scope, List<GrantAction> actions, int durationMinutes, String reason, List<String> approvers) Approver-set form without a name restriction (D-37).create(GrantScope scope, List<GrantAction> actions, int durationMinutes, String reason, List<String> approvers, String createNamePattern) Creates a PENDING grant request designating an approver set (D-37) and, for CREATE, an optional name restriction (D-40): an exact item name or a/regex/matched against the whole name of the new item.voidExpires PENDING grant requests pastpendingTimeoutHours.static ItemfindScopeItem(String fullName) D-71: the item a window would name, as the current user sees it, ornullwhen no item exists atfullNameor the user may not read it (an item visible only through Item/Discover counts as not visible).static GrantRequestServiceget()list()All stored grant requests, in creation order.Loads a grant request by id, ornull.voidD-36: sendsNotificationEvent.EXPIRINGonce for every PENDING grant request whose pending timeout falls withinnotifyBeforeExpiryMinutes, andNotificationEvent.GRANT_EXPIRINGonce for every active window ending within it.voidrefuseRequestWhileChangeControlOff(String scopeFullName) e2e-03 DEF-27: the refusal of a grant request that the HTTP layer turns away before it reachescreate(io.jenkins.plugins.batchcontrol.model.GrantScope, java.util.List<io.jenkins.plugins.batchcontrol.model.GrantAction>, int, java.lang.String, java.lang.String)(the Grants screen closes with the change-control switch).Rejects a PENDING grant request; the comment is mandatory (SPEC item 5 rule reused).
-
Method Details
-
get
-
load
Loads a grant request by id, ornull. -
list
All stored grant requests, in creation order. -
countPendingFor
D-61: the PENDING grant requests that concernauth, read from the open-request index only (no history scan): those awaiting their decision as a designated approver holding Jenkins-levelBatchControl/Approve, else their own. Every counted request is visible toauthunder P-09. The single source for the tab badge and the section. -
create
public GrantRequest create(GrantScope scope, List<GrantAction> actions, int durationMinutes, String reason, String approver) Creates a PENDING grant request. The requester is the current authentication; validation failures throwIllegalArgumentException.Rules: at least one action; duration in
(0, maxGrantMinutes]; non-empty reason of at most 4000 characters; the approver must be on the global list and must not be the requester (admin exception per the self-approval policy); the scope item must exist and be visible to the requester, and each action must apply to its kind (D-71: CREATE only on a regular folder, DELETE only on a job). -
create
public GrantRequest create(GrantScope scope, List<GrantAction> actions, int durationMinutes, String reason, List<String> approvers) Approver-set form without a name restriction (D-37). -
create
public GrantRequest create(GrantScope scope, List<GrantAction> actions, int durationMinutes, String reason, List<String> approvers, String createNamePattern) Creates a PENDING grant request designating an approver set (D-37) and, for CREATE, an optional name restriction (D-40): an exact item name or a/regex/matched against the whole name of the new item. A blank restriction means none; an invalid one (bad regex, invalid item name, over 1000 characters) is refused withIllegalArgumentException, as is a restriction on a request without CREATE. -
findScopeItem
D-71: the item a window would name, as the current user sees it, ornullwhen no item exists atfullNameor the user may not read it (an item visible only through Item/Discover counts as not visible). The single lookup used for requests and approvals. -
approve
Approves a PENDING grant request and creates the grant. The caller must be the designated approver holding the Approve permission (or the admin self-approval path). The grant window is[now, now + durationMinutes)on theBatchClock; SPEC item 8: the requester holds the permissions immediately.The stored scope is re-validated here (S-13, D-71): approval fails with
IllegalStateExceptionif no item exists at the scope name any more or its kind (descriptor id) differs from the one recorded at creation, and withIllegalArgumentExceptionfor a root scope or an item the approver cannot see (T-SEC-18): the approver must be able to see the scope item to approve a window on it.D-71c (3): if the item is deleted after it was checked and before the window is registered, the window ends at once; the request stays APPROVED and its APPROVED notice says that the window ended at once and why (owner decision 2026-10-06).
- Returns:
- the created, immediately effective
Grant, or the window that ended at once
-
reject
Rejects a PENDING grant request; the comment is mandatory (SPEC item 5 rule reused). -
changeApprovers
Replaces the designated approver set of a PENDING grant request; requester only (SPEC item 3 rules reused, D-26, D-37). Recorded as (previous set, new set, changed by, time). -
cancel
Cancels a PENDING grant request; requester or a Manage holder only (SPEC item 7 rule). -
expireOverduePending
public void expireOverduePending()Expires PENDING grant requests pastpendingTimeoutHours. Called by the periodic work; expiry truth stays the clock comparison (a late approval attempt expires the request on its own, seeapprove(java.lang.String, java.lang.String)). -
notifyExpiring
public void notifyExpiring()D-36: sendsNotificationEvent.EXPIRINGonce for every PENDING grant request whose pending timeout falls withinnotifyBeforeExpiryMinutes, andNotificationEvent.GRANT_EXPIRINGonce for every active window ending within it. The "notified" flags are persisted before dispatch, so a restart never resends.One request or window that cannot be read or written never keeps the others from their notice: the pending requests and the windows are handled apart, each request and each window on its own, and a failure is logged.
-
refuseRequestWhileChangeControlOff
e2e-03 DEF-27: the refusal of a grant request that the HTTP layer turns away before it reachescreate(io.jenkins.plugins.batchcontrol.model.GrantScope, java.util.List<io.jenkins.plugins.batchcontrol.model.GrantAction>, int, java.lang.String, java.lang.String)(the Grants screen closes with the change-control switch). Records the refused request exactly ascreate(io.jenkins.plugins.batchcontrol.model.GrantScope, java.util.List<io.jenkins.plugins.batchcontrol.model.GrantAction>, int, java.lang.String, java.lang.String)would and throws the sameIllegalStateException; returns normally while change control is on.- Parameters:
scopeFullName- the scope the request named, ornullwhen none was given- Throws:
IllegalStateException- if change control is off
-