Class GrantsSection
- All Implemented Interfaces:
ModelObject,org.kohsuke.stapler.StaplerProxy
/batch-control/grants/ (SPEC item 8, JIT permission requests).
URL space (fixed contract, asserted by tests):
/batch-control/grants/— pending requests, active and ended windows (served fromindex.jelly; PUT/DELETE/PATCH get 405). D-66: no form here; the old prefill links (?scopeFullName=,?from=) are redirected tonew/batch-control/grants/new— the new request form as a page;/batch-control/grants/dialog— the same form for core's dialog (D-66)POST /batch-control/grants/create— submit a new grant requestPOST /batch-control/grants/checkScopeFullName— the form's check of the item name (D-71): its kind, or "No such item"/batch-control/grants/<id>/— request detail; POSTapprove/reject/cancel/revoke(seeGrantRequestItem)POST /batch-control/grants/active/<grantId>/revoke— revoke an active grant (seeActiveGrantsSection)
No state transition logic lives here; everything is delegated to
GrantRequestService and GrantService. Viewing requires one of the plugin
permissions (requesters see their requests, approvers their inbox, managers the active
grants), and the whole subtree additionally closes while change control is off — both enforced
by getTarget(). The one exception to the closure is POST <id>/approve, which
goes on to GrantRequestService.approve(java.lang.String, java.lang.String) so that the service refuses and records the
approval (LIMITATIONS 29).
The switch closes this screen and nothing else. It must never reach the audit trail: the Change Records and History screens keep showing the windows that existed and the changes made under them, because a switch flip that retroactively hid audit records would be a worse defect than the one the gate fixes.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classOne row of the Grants lists: a grant request and, once approved, its permission window (the window carries the request's id). -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intPage size for both the request list and the active grant list. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionThe CREATE name restriction of a row in words (DEF-19): the pattern, "any name" for an unrestricted CREATE, empty when the row does not include CREATE.doCheckScopeFullName(String value) POST/batch-control/grants/checkScopeFullName— the request form's check of the item name (D-71): the kind of the job or folder the window would name, for examplePipeline 'team/nightly', so the requester sees what they are asking for before submitting.voiddoCreate(org.kohsuke.stapler.StaplerRequest2 req, org.kohsuke.stapler.StaplerResponse2 rsp) POST/batch-control/grants/create— submits a new grant request.endedAt(GrantsSection.Row row) When a row ended: its window's end, else the request's decision (or creation).When a grant ended: its revocation time, else its expiry.endedLabel(Grant grant) How a grant ended, in words: "Expired", "Revoked by admin", or for a revocation by the change control switch "Revoked (change control turned off) by admin".formatParts(Instant instant) e2e-09 DEF-01: a timestamp as its date and its time-with-zone, for the grant tables, which render each part unbroken so that a narrow window breaks a cell only between them (never inside a date) and the page does not scroll sideways at 1280 px.Stapler: serves/batch-control/grants/active/...(revoke endpoints).Open permission windows on the current page, most recently granted first.intintApprover candidates (global list minus the current user, per the self-approval policy).intMaximum length of the CREATE name restriction, for the form'smaxlength.Preset duration choices from the global configuration.getDynamic(String id) Stapler: serves/batch-control/grants/<id>/;nullrenders a 404.Ended windows and requests that never became one (rejected, cancelled, expired), on the current page, most recently ended first.intintThe refusal of the new-request form on this request, or an empty one (DEF-09, Jelly).D-66: the query string to carry from an old prefill link of the list page (/batch-control/grants/?scopeFullName=...or?from=...) to the form page, ornullwhen the list page was opened without one.intUpper bound in minutes for a grant request (client-side cap; the service re-checks).Pending grant requests on the current page, oldest first (closest to its timeout on top).intintThe renewed grant's CREATE name restriction, or empty.Full name the new-request form starts with: the renewed grant's scope (D-33), else?scopeFullName=— howJobGrantRequestActionhands the job over, so a user who arrives from a job page does not have to retype its path (U-01).D-75 (1), security-39 S-39-04: the name the form's prefill note shows for the renewed grant's item (tags/scopeItem.jelly), ornullwhen the form renews nothing.The ended grant the form renews (?from=<grantId>), ornull.Permissions for this screen'sl:layout(the same set its section gate checks).How a row ended, in words: the window's end, else the request's outcome.booleanWhether the re-request button is shown: the caller's own ended window, and may request.booleanView gating for the new-request form;doCreate(org.kohsuke.stapler.StaplerRequest2, org.kohsuke.stapler.StaplerResponse2)re-checks for real.booleanView gating for the Revoke buttons; the revoke endpoint re-checks for real.booleanbooleanbooleanbooleanbooleanbooleanbooleanisPrefillAction(String action) Whether the action checkbox starts checked: the renewed grant's actions; else the?actions=values (matched againstGrantAction, how a refusal such as the delete veto hands over the action it needs, DEF-26); else CONFIGURE when the form was opened for an item.booleanisPrefillDuration(int minutes) Whether the presetminutesstarts selected: the renewed grant's length when it is one of the presets.booleanWhether the form was opened for a specific item: from a job's "Request Change Permission" entry (CONFIGURE then starts checked, the user is trying to change that job) or from the re-request link of an ended grant (its actions start checked, D-33).booleanWhether the form was opened for a folder where a window's Create applies (?scopeFullName=resolves, as the viewer, to a regular folder; D-71: not a job and not a computed folder such as a multibranch project or an organization folder).join(Collection<?> items) Jelly helper: comma-joined action list ("CREATE, CONFIGURE").minutesLabel(int minutes) Jelly helper:1 minute/15 minutesfor the duration select (UX-12).Jelly helper: how much of a grant window is left (12 min 30 sec), so the user does not have to subtract the absolute expiry time from the current time (UX-11).
-
Field Details
-
PAGE_SIZE
public static final int PAGE_SIZEPage size for both the request list and the active grant list.- See Also:
-
-
Constructor Details
-
GrantsSection
public GrantsSection()
-
-
Method Details
-
getTarget
- Specified by:
getTargetin interfaceorg.kohsuke.stapler.StaplerProxy
-
getDisplayName
- Specified by:
getDisplayNamein interfaceModelObject
-
getViewPermissions
Permissions for this screen'sl:layout(the same set its section gate checks). -
getDynamic
Stapler: serves/batch-control/grants/<id>/;nullrenders a 404. A grant request the caller may not see (P-09, S-01) renders exactly like a nonexistent one so its existence is not disclosed, and so does every failed lookup (S-39-01,RecordLookup). -
getActive
Stapler: serves/batch-control/grants/active/...(revoke endpoints). -
doCreate
public void doCreate(org.kohsuke.stapler.StaplerRequest2 req, org.kohsuke.stapler.StaplerResponse2 rsp) throws IOException, jakarta.servlet.ServletException POST/batch-control/grants/create— submits a new grant request. This method only parses HTTP input; all business validation (action set non-empty, duration cap, approver eligibility, reason required) is enforced byGrantRequestService.create(io.jenkins.plugins.batchcontrol.model.GrantScope, java.util.List<io.jenkins.plugins.batchcontrol.model.GrantAction>, int, java.lang.String, java.lang.String).Form fields:
scopeFullName(the one job or folder the window names, D-71; ascopeTypefield sent by an earlier form is ignored),actions(multi-valued checkboxes),durationMinutes(preset select),customDurationMinutes(optional free number overriding the preset, capped client-side atmaxGrantMinutesand re-checked by the service),reason,approvers(repeated, one user id each; D-37) and the optionalcreateNamePattern(exact name or/regex/, CREATE only; D-40). The form shows the name restriction only while Create is ticked, so it is read only for a request that includes CREATE, as core'sf:optionalBlockdoes not count the fields of a collapsed block.- Throws:
IOExceptionjakarta.servlet.ServletException
-
getLegacyFormQuery
D-66: the query string to carry from an old prefill link of the list page (/batch-control/grants/?scopeFullName=...or?from=...) to the form page, ornullwhen the list page was opened without one. Only the prefill parameters are carried, each URL-encoded; the form page resolves them again before it shows anything. -
getFormErrors
The refusal of the new-request form on this request, or an empty one (DEF-09, Jelly). -
doCheckScopeFullName
POST/batch-control/grants/checkScopeFullName— the request form's check of the item name (D-71): the kind of the job or folder the window would name, for examplePipeline 'team/nightly', so the requester sees what they are asking for before submitting. Read-only;doCreate(org.kohsuke.stapler.StaplerRequest2, org.kohsuke.stapler.StaplerResponse2)and the service decide for real.The item is looked up as the caller (
GrantRequestService.findScopeItem(java.lang.String)): an item that does not exist and one the caller may not read (Item/Discover only included) get the same answer, so the check cannot be used to probe for names. The answer only repeats the item's own full name and its descriptor's display name. A blank field gets no message (the form is not filled in yet; submitting it is refused next to the field).spec-review-S6 M-1: the kind is shown with its icon, as in the lists (
tags/scopeItem.jelly), so the answer is markup (kindMarkup(io.jenkins.plugins.batchcontrol.model.ItemKind, java.lang.String)). -
isCanRequest
public boolean isCanRequest()View gating for the new-request form;doCreate(org.kohsuke.stapler.StaplerRequest2, org.kohsuke.stapler.StaplerResponse2)re-checks for real. -
isCanRevoke
public boolean isCanRevoke()View gating for the Revoke buttons; the revoke endpoint re-checks for real. -
getDurationOptions
Preset duration choices from the global configuration. -
getCreateNamePatternMaxLength
public int getCreateNamePatternMaxLength()Maximum length of the CREATE name restriction, for the form'smaxlength. -
getMaxGrantMinutes
public int getMaxGrantMinutes()Upper bound in minutes for a grant request (client-side cap; the service re-checks). -
getApproverOptions
Approver candidates (global list minus the current user, per the self-approval policy). -
formatParts
e2e-09 DEF-01: a timestamp as its date and its time-with-zone, for the grant tables, which render each part unbroken so that a narrow window breaks a cell only between them (never inside a date) and the page does not scroll sideways at 1280 px. Empty for null. -
remaining
Jelly helper: how much of a grant window is left (12 min 30 sec), so the user does not have to subtract the absolute expiry time from the current time (UX-11).- Returns:
- the remaining span, or
"expired"once the window has closed (a grant can still be listed for the moment between expiry and the sweeper run)
-
minutesLabel
Jelly helper:1 minute/15 minutesfor the duration select (UX-12). -
isPrefilledForFolder
public boolean isPrefilledForFolder()Whether the form was opened for a folder where a window's Create applies (?scopeFullName=resolves, as the viewer, to a regular folder; D-71: not a job and not a computed folder such as a multibranch project or an organization folder). -
getPrefillScopeFullName
Full name the new-request form starts with: the renewed grant's scope (D-33), else?scopeFullName=— howJobGrantRequestActionhands the job over, so a user who arrives from a job page does not have to retype its path (U-01).The parameter is resolved, never echoed: the name is looked up through
Visibility.findVisibleItem(java.lang.String)and what the form receives is the model object's owngetFullName(). An item that does not exist, or that the caller cannot see, yields an empty field, so this cannot be used to reflect arbitrary text into the page or to probe for names — it renders exactly what a caller could already read from the item's own URL. A renewed grant is likewise resolved from the store, and only the caller's own; its item's name is the onegetRenewScope()shows (D-75 (1)).- Returns:
- the canonical full name, or an empty string when there is nothing to prefill
-
isPrefilled
public boolean isPrefilled()Whether the form was opened for a specific item: from a job's "Request Change Permission" entry (CONFIGURE then starts checked, the user is trying to change that job) or from the re-request link of an ended grant (its actions start checked, D-33). -
getRenewScope
D-75 (1), security-39 S-39-04: the name the form's prefill note shows for the renewed grant's item (tags/scopeItem.jelly), ornullwhen the form renews nothing. A window's followed name only to a viewer who may read the item now; otherwise the approved name with the fixed "moved" note, and the name field starts empty (getPrefillScopeFullName()). -
getRenewSource
The ended grant the form renews (?from=<grantId>), ornull. -
isPrefillAction
Whether the action checkbox starts checked: the renewed grant's actions; else the?actions=values (matched againstGrantAction, how a refusal such as the delete veto hands over the action it needs, DEF-26); else CONFIGURE when the form was opened for an item. -
getPrefillCreateNamePattern
The renewed grant's CREATE name restriction, or empty. -
isPrefillDuration
public boolean isPrefillDuration(int minutes) Whether the presetminutesstarts selected: the renewed grant's length when it is one of the presets. Otherwise none is marked and the browser shows the first option. -
getPendingItems
Pending grant requests on the current page, oldest first (closest to its timeout on top). -
getPendingPage
public int getPendingPage() -
getPendingTotal
public int getPendingTotal() -
isHasPendingPrevious
public boolean isHasPendingPrevious() -
isHasPendingNext
public boolean isHasPendingNext() -
getActiveItems
Open permission windows on the current page, most recently granted first. -
getActivePage
public int getActivePage() -
getActiveTotal
public int getActiveTotal() -
isHasActivePrevious
public boolean isHasActivePrevious() -
isHasActiveNext
public boolean isHasActiveNext() -
getEndedItems
Ended windows and requests that never became one (rejected, cancelled, expired), on the current page, most recently ended first. SPEC item 8 (D-33): the history of expired windows with a re-request link. -
getEndedPage
public int getEndedPage() -
getEndedTotal
public int getEndedTotal() -
isHasEndedPrevious
public boolean isHasEndedPrevious() -
isHasEndedNext
public boolean isHasEndedNext() -
endedLabel
How a grant ended, in words: "Expired", "Revoked by admin", or for a revocation by the change control switch "Revoked (change control turned off) by admin". -
endedAt
When a grant ended: its revocation time, else its expiry. -
endedAt
When a row ended: its window's end, else the request's decision (or creation). -
howEnded
How a row ended, in words: the window's end, else the request's outcome. -
isCanRenew
Whether the re-request button is shown: the caller's own ended window, and may request. -
createNameLabel
The CREATE name restriction of a row in words (DEF-19): the pattern, "any name" for an unrestricted CREATE, empty when the row does not include CREATE. -
join
Jelly helper: comma-joined action list ("CREATE, CONFIGURE").
-