Class GrantService
grants/<id>.xml), so the permission-check hot path
(GrantAwareACL) never touches disk.
Restart safety: Jenkins is a singleton, so there is exactly one live cache to keep
fresh; resetCacheOnStartup() clears it unconditionally on every Jenkins startup, so
the very first query after a restart reloads straight from the files instead of serving
whatever happened to be in memory before. A grant that is still inside its window therefore
survives a restart and one whose window ended during the downtime is gone from the very first
check (SPEC item 8). Activity is always judged by Grant.isActiveAt(java.time.Instant) against
BatchClock at check time — no timers.
S-15: the change-control switch gates whether a grant confers anything (that check is
in GrantAwareACL), and turning the switch off also closes the windows that are open at
that moment — see revokeAllActive().
D-74: a window names one item by its full name and follows that item. Item events keep the
names right (WindowItemListener): a rename or move updates the windows naming the item
(followItem(hudson.model.Item, java.lang.String, java.lang.String)), a deletion ends them (endWindowsOf(hudson.model.Item, java.lang.String)). Renaming through a window is
refused (D-71c, GrantAwareACL), so only an administrator or a user with their own
permissions can move a window's name. S-39-02: no window or D-35c record is left on a name its
item no longer has: registration verifies the approved item is still at its name
(register(io.jenkins.plugins.batchcontrol.model.Grant, hudson.model.Item), D-71c (3)), and a window that cannot follow its item for certain ends instead
(followItem(hudson.model.Item, java.lang.String, java.lang.String)). D-35c created-item records and, D-75 (2), the D-58a changed-under-grant
lists follow in memory first and their write is retried; an entry at a name another item has just
taken is dropped (relocateCreatedItem(hudson.model.Item, java.lang.String, java.lang.String), relocateChanged(hudson.model.Item, java.lang.String, java.lang.String)).
D-74, a window's end is never lost: a window ends in memory first, so it confers nothing from
that moment, and its GRANT_REVOKE record is appended before its file is rewritten. If the
file cannot be written, the end is kept in unsavedEnds and written again before every
later grant write, by every item event and by the periodic work (flushUnsavedEnds());
every read of a grant file in this class applies it, so no other write can bring the window back.
If Jenkins stops before the end is written, the record stands in for it: when the cache is
loaded, a window whose file still says it is open but which has a GRANT_REVOKE record
is ended again (applyRecordedEnds(java.util.List<io.jenkins.plugins.batchcontrol.model.Grant>)), so a restart cannot re-open it, also not on an item
created at its name in the meantime. S-39-03: that read is bounded by time, not by a record
count, and when it cannot be completed every open window ends (fail-closed).
-
Method Summary
Modifier and TypeMethodDescriptionD-36: marks and returns every active grant whose window ends withinleadand whose GRANT_EXPIRING notification was not sent yet.voidclearStaleEntry(String fullName) S-29-04: an administrator clears a listed entry whose item no longer resolves (a stale entry).voidendWindowsOf(Item item, String user) D-74: the itemfullNamewas deleted; every active window naming it, or an item below it, ends: it is revoked byuser, withGrant.REVOKED_ITEM_DELETEDas the reason and aGRANT_REVOKErecord, so it keeps its history.voidendWindowsOfMissingItems(Predicate<String> exists) D-74: after all items are loaded at startup, ends every active window whose item no longer exists (existsis false for its full name): it was deleted while Jenkins was down, or Jenkins stopped between deleting it and handling the deletion.voidendWindowsOnNewItem(Item created) D-74: a new item was created (or copied) underfullName.findActiveCreateGrant(String user, ItemGroup<?> group, String itemName) D-40: the first active Create grant ofuseron the item groupgroup(named exactly) whose name restriction (if any) allowsitemName, ornull.findActiveDeleteGrant(String user, Item item) D-71: the active DELETE window ofuseronitem, ornull.findActiveDeleteGrant(String user, Item item, String itemFullName) AsfindActiveDeleteGrant(String, Item)for the item under the nameitemFullName(its name before a move, for example).findActiveGrant(String user, Item item, GrantAction action) The first active grant ofusernaming exactlyitem's full name and includingaction(null: any action), ornull.findActiveGrant(String user, String itemFullName, Item item, GrantAction action) AsfindActiveGrant(String, Item, GrantAction)for a window namingitemFullNamerather than the item's current full name: its name before a rename or move, whose window was the one in use (change records; item events update the window's name only after those are written,WindowItemListener).findActiveGrant(String user, String itemFullName, GrantAction action) The first active grant ofuserwhose scope is the itemitemFullName(an item the caller can see must be at that name) and that includesaction, ornull.findActiveGrants(String user, Item item, GrantAction action) Every active grant ofusernaming exactlyitem's full name and includingaction(D-40: the CREATE check has to see all of them, since each may carry a different name restriction).findConfigureGrant(String user, Item item) The active grant that givesuserItem/Configure onitem: a grant with the CONFIGURE action naming the item, or a Create grant through which the user created it (D-35c).findCreatingGrant(String user, Item item) D-35c: the active grant ofuserthrough whose Createitemwas created, ornull.findCreatingGrant(String user, String itemFullName, Item item) AsfindCreatingGrant(String, Item)for the record under the nameitemFullName(its name before a rename, whose record was the one in use); the parent isitem's.voidD-74: writes the ends (and, S-39-02, the created-item records, and, D-75 (2), the changed-item lists) that could not be written so far (called by the periodic work; every grant write and every item event does the same first).voidfollowItem(Item moved, String oldFullName, String newFullName) D-74: the itemmovedwas renamed or moved fromoldFullNametonewFullName; every active window naming exactlyoldFullNamenow namesnewFullName.voidforgetChanged(String fullName) D-58a: a deleted item (and what was below it) leaves the "changed under a grant" state.voidforgetCreatedItem(String fullName) D-35c: an item recorded as created through an active grant was deleted.voidforgetDeleted(Collection<String> grantIds) Drops grants that retention has deleted from the store.voidforgetStaleCreatedItem(Item created) D-35c, D-74: a new item was created underfullName; a created-item record under that name belongs to an item that disappeared without a deletion event (deleted on disk and reloaded) and is dropped, so it never applies to the new item.static GrantServiceget()guardingGrantId(String itemFullName) D-58a: the id of a grant that makes the item guarded (one that lists it as changed, else an active one covering it), ornullwhen it is not guarded.booleanhasActiveGrant(String user, String itemFullName, Permission permission) Whetherusercurrently holdspermissionon the item nameditemFullNamethrough an active grant.booleanisChangedUnderGrant(Item item) D-58b: whether the item, or an item above it, is in the "changed under a grant" state (any grant, active or ended).booleanisGuardedItem(String itemFullName) D-58a: whether the item is guarded: covered by an active grant (its scope includes the item, the scope lies below the item when the item is a folder, or the item was created through it), or changed under a grant (active or ended) and not reviewed since.itemsChangedUnderGrant(int limit) D-58a: the items in the "changed under a grant" state, sorted, at mostlimit.Every grant that is active right now (not expired, not revoked).listAll()Every known grant, active or ended, as the permission checks see it (a copy of the list): an end not yet written to its file is already in it.voidmarkChanged(String grantId, String itemFullName) D-58a: notes thatitemFullNamewas changed undergrantId(a save or creation by the holder while their permission came only from the grant), persisting the grant.markedRuns(Item item) D-58c: the ids (job#number) of the runs of the item (a job, or the jobs below a folder) that were replayed under a grant, at most 50.voidmarkReviewed(Item item) D-58b (3): the deliberate review.voidnoteMarkedRun(String jobFullName, String runId) D-58c: a marked run started (called by the run listener).voidpruneCreatedItems(Predicate<String> exists) D-35c, S-09: drops from the created-items lists of active grants every item for whichexistsis false.recordCreatedItem(String user, Item item) D-35c: notes thatusercreateditemthrough the Create of an active grant, persisting the grant.booleanPersists a freshly created grant and makes it effective immediately.booleanregisterApproved(Item item, Supplier<Grant> approval) #39: the approval's registration.voidrelocateChanged(Item moved, String oldFullName, String newFullName) D-58a (S-27-03): an item was renamed or moved.voidrelocateCreatedItem(Item moved, String oldFullName, String newFullName) D-35c: the itemmoved, recorded as created through an active grant, was renamed or moved fromoldFullNametonewFullName; the record follows it.static voidClears the in-memory cache.Immediately revokes a grant (SPEC item 8: Manage holders only — the web action checks; the service double-checks) and appends aChangeRecord(GRANT_REVOKE).intS-15, the kill switch: revokes every grant that is active right now and returns how many were closed.
-
Method Details
-
get
-
resetCacheOnStartup
Clears the in-memory cache. Jenkins is a singleton, so this is not about telling one running instance apart from another — it simply makes sure the first query after a fresh Jenkins startup (a real restart, or a test harness booting a new session) reloads from the files instead of serving a cache built for whatever was on disk before. -
forgetDeleted
Drops grants that retention has deleted from the store. They ended before the retention cut-off, so none of them can be active; this only keeps the cache from holding them until the next restart. -
hasActiveGrant
Whetherusercurrently holdspermissionon the item nameditemFullNamethrough an active grant. Only the three grantable item permissions can ever match; any other permission returnsfalseimmediately.The item currently at that name is resolved as the caller sees it; none, no grant. Whether the action can apply to the item's kind is decided when the request is submitted and approved, and again by the grant layer (
GrantAwareACL) andfindActiveDeleteGrant(java.lang.String, hudson.model.Item). -
findActiveGrant
@CheckForNull public Grant findActiveGrant(String user, String itemFullName, @CheckForNull GrantAction action) The first active grant ofuserwhose scope is the itemitemFullName(an item the caller can see must be at that name) and that includesaction, ornull. Anullaction matches any action.For DELETE this does not look at the item's kind; callers holding the item use
findActiveDeleteGrant(java.lang.String, hudson.model.Item), which also requires the item to be a job (D-71). -
findActiveGrant
@CheckForNull public Grant findActiveGrant(String user, @CheckForNull Item item, @CheckForNull GrantAction action) The first active grant ofusernaming exactlyitem's full name and includingaction(null: any action), ornull. -
findActiveGrant
@CheckForNull public Grant findActiveGrant(String user, @CheckForNull String itemFullName, @CheckForNull Item item, @CheckForNull GrantAction action) AsfindActiveGrant(String, Item, GrantAction)for a window namingitemFullNamerather than the item's current full name: its name before a rename or move, whose window was the one in use (change records; item events update the window's name only after those are written,WindowItemListener). -
findActiveDeleteGrant
D-71: the active DELETE window ofuseronitem, ornull. A window's DELETE applies only to a job (GrantScope.deleteAppliesTo(hudson.model.Item)), so for any other item — a folder, a multibranch project, an organization folder — this isnullwhatever windows exist: deleting such a group would delete its children as SYSTEM. -
findActiveDeleteGrant
@CheckForNull public Grant findActiveDeleteGrant(String user, @CheckForNull Item item, @CheckForNull String itemFullName) AsfindActiveDeleteGrant(String, Item)for the item under the nameitemFullName(its name before a move, for example). -
findActiveGrants
Every active grant ofusernaming exactlyitem's full name and includingaction(D-40: the CREATE check has to see all of them, since each may carry a different name restriction).For
GrantAction.CREATE,itemis the item group the new item is created in (Item/Create is checked on the group's ACL), so a CREATE window confers Create in its own folder only, never in a nested folder or at the root (D-71). -
findActiveCreateGrant
@CheckForNull public Grant findActiveCreateGrant(String user, @CheckForNull ItemGroup<?> group, String itemName) D-40: the first active Create grant ofuseron the item groupgroup(named exactly) whose name restriction (if any) allowsitemName, ornull.nullfor the Jenkins root, where no window exists (S-13). -
claimExpiringNotifications
D-36: marks and returns every active grant whose window ends withinleadand whose GRANT_EXPIRING notification was not sent yet. The flag is persisted before the caller dispatches, so a restart never resends.Each window is claimed on its own: a grant file that cannot be read or written now is logged and left unclaimed for the next run, and it never keeps the windows after it from being claimed nor drops the claims already written, which are all returned (a claim written but not returned would never be sent).
-
findCreatingGrant
D-35c: the active grant ofuserthrough whose Createitemwas created, ornull. While such a grant is active its holder also holds Item/Read and Item/Configure on that item (seeGrantAwareACL), so matrix-auth's creator listener finds the permissions already held and writes no permanent entry; the permissions end with the window.The item must still lie directly inside the grant's scope folder, matched by parent, not by name prefix (D-71). Item events keep the record's name right (D-74): a rename or move updates it, a deletion drops it, and a new item arriving under a recorded name drops the record (
forgetStaleCreatedItem(hudson.model.Item)), so the record never applies to an item someone else made. -
findCreatingGrant
@CheckForNull public Grant findCreatingGrant(String user, @CheckForNull String itemFullName, @CheckForNull Item item) AsfindCreatingGrant(String, Item)for the record under the nameitemFullName(its name before a rename, whose record was the one in use); the parent isitem's. -
findConfigureGrant
The active grant that givesuserItem/Configure onitem: a grant with the CONFIGURE action naming the item, or a Create grant through which the user created it (D-35c).nullif neither exists. Used to name the grant a change or a violation came from (D-35b, SPEC item 9). -
isGuardedItem
D-58a: whether the item is guarded: covered by an active grant (its scope includes the item, the scope lies below the item when the item is a folder, or the item was created through it), or changed under a grant (active or ended) and not reviewed since. Answered from the in-memory grant cache. -
noteMarkedRun
D-58c: a marked run started (called by the run listener). -
markedRuns
D-58c: the ids (job#number) of the runs of the item (a job, or the jobs below a folder) that were replayed under a grant, at most 50. Served from the in-memory index; no build is loaded. -
isChangedUnderGrant
D-58b: whether the item, or an item above it, is in the "changed under a grant" state (any grant, active or ended). Served from the in-memory grant cache, for page rendering. -
guardingGrantId
D-58a: the id of a grant that makes the item guarded (one that lists it as changed, else an active one covering it), ornullwhen it is not guarded. -
itemsChangedUnderGrant
D-58a: the items in the "changed under a grant" state, sorted, at mostlimit. -
markChanged
D-58a: notes thatitemFullNamewas changed undergrantId(a save or creation by the holder while their permission came only from the grant), persisting the grant. The mark is in effect in memory at once and a failed write is retried (rewriteChangedItems(io.jenkins.plugins.batchcontrol.model.Grant, java.util.function.UnaryOperator<java.util.List<java.lang.String>>, java.lang.String)); it never fails the save. -
markReviewed
D-58b (3): the deliberate review. The item and everything below it leave the "changed under a grant" state, and aGUARD_REVIEWEDchange record names the reviewer. The caller must hold Item/Configure on the item natively (asked with every grant layer off) or Overall/Administer; a user whose permission on the item comes from a grant cannot review it. The entries leave the state in memory at once and a grant file that cannot be written is written again later (removeChanged(java.util.Set<java.lang.String>)), so the record says what the guard does.- Throws:
org.springframework.security.access.AccessDeniedException- (AccessDeniedException3) when the caller may not review the item
-
clearStaleEntry
S-29-04: an administrator clears a listed entry whose item no longer resolves (a stale entry). Checked here too: Overall/Administer. -
relocateChanged
D-58a (S-27-03): an item was renamed or moved. The "changed under a grant" state follows it and what is below it; and an item that was covered by an active grant under its old name, but is not under its new name, is marked as changed under that grant, so it stays guarded. A window naming the item or an item below it follows it (D-74,followItem(hudson.model.Item, java.lang.String, java.lang.String)), so it keeps covering the item and marks nothing.D-75 (2), as for created-item records (
relocateCreatedItem(hudson.model.Item, java.lang.String, java.lang.String)): an entry already namingnewFullName(in any letter case) or an item below it, other than the moved item's own entries, cannot be about the moved item, which only now took that name; it is dropped first, so the moved item does not inherit another item's state. An entry whose own item is still at exactly its name, next to the moved item, stays (DEF-E17-01,ownItemStillAt(java.lang.String, hudson.model.Item)). The entries change in the cache first and their write is retried (rewriteChangedItems(io.jenkins.plugins.batchcontrol.model.Grant, java.util.function.UnaryOperator<java.util.List<java.lang.String>>, java.lang.String)).T-GAP-320: core reports the location change of a folder and then of every item below it, each with its own old and new name, and this drop runs again in each of those events. So the entries of the items below a renamed or moved folder follow in their own item's event, exact names first, as windows and created-item records do (
entriesFollowingLater(hudson.model.Item, java.lang.String, java.lang.String)); were they moved here, the drop of the later event would take them for stale entries at a name the item below has just taken. An entry below the item that no item below it carries (its item is gone, so no event of its own comes) follows here.- Parameters:
moved- the renamed or moved item (nullwhen unknown)
-
forgetChanged
D-58a: a deleted item (and what was below it) leaves the "changed under a grant" state. -
listActive
Every grant that is active right now (not expired, not revoked). -
register
Persists a freshly created grant and makes it effective immediately. Called only bypolicy.GrantRequestServiceon approval, with the item the approval checked.D-74: item events do not wait for the approval, so the item may have been renamed or moved after it was checked and before this runs; the event then found no window to update. The window is therefore written under the item's full name as it is now. From here on, every event sees the window: item events are handled under this monitor too.
D-71c (3), S-39-02: the item may also have been deleted after it was checked, and another item created, renamed or moved to its name; neither event found a window to end. So the item's identity is verified here, under this monitor, before the window becomes effective: unless the item at its full name is still the approved object and its deletion has not been reported, the window ends at once, with
Grant.REVOKED_ITEM_DELETEDas the reason and aGRANT_REVOKErecord, like any other end (revokeOne(io.jenkins.plugins.batchcontrol.model.Grant, java.lang.String, java.lang.String, java.lang.String)).- Returns:
truewhen the window is in effect;falsewhen it ended at once because its item was deleted (the caller's APPROVED notice says so, owner decision 2026-10-06)
-
registerApproved
#39: the approval's registration.approvaldecides the request and returns the window to register; it runs under this monitor, and the window is registered asregister(Grant, Item)does before the monitor is released.Why under this monitor: turning change control off writes the switch first and then calls
revokeAllActive(), which holds this monitor while it ends every active window. A switch check made insideapprovalis therefore atomic with the registration relative to that revocation. Either the check runs first, so the window is in the cache whenrevokeAllActivelists it and the switch-off ends it, or it runs after, sees the switch off, and refuses before anything is decided or registered. No window can be registered after a switch-off has returned.Lock order, which this method keeps acyclic:
policy.GrantRequestService's lock, then this monitor, then the store. The switch-off path takes the configuration's monitor and then this monitor. Nothing that runs under this monitor (includingapproval) takes the configuration's monitor orGrantRequestService's lock: the switch is a volatile read.- Parameters:
approval- decides the request (re-checks the switch, persists the decision) and returns the window to register; an exception it throws registers nothing- Returns:
- as
register(Grant, Item)
-
recordCreatedItem
D-35c: notes thatusercreateditemthrough the Create of an active grant, persisting the grant. Called bylistener.CreatedItemGrantListeneronly when the creation was not possible without the grant. The Create window is the one on the item's parent folder whose name restriction admits the item's name (D-40, chosen outside the monitor, S-03).- Returns:
- the grant that now records the item, or
nullwhen no active Create grant ofusercovers the item
-
relocateCreatedItem
D-35c: the itemmoved, recorded as created through an active grant, was renamed or moved fromoldFullNametonewFullName; the record follows it. Whether it still confers anything is decided by the parent check at query time, so moving the item out of the scope folder ends the permission. Core reports the change for every item below a renamed or moved folder too, so each record follows in its own item's event (exact names, as windows do).S-39-02, as for windows (
followItem(hudson.model.Item, java.lang.String, java.lang.String)): a record already namingnewFullName(in any letter case, other than the moved item's own old name) cannot be about the moved item and is dropped first, unless its own item is still at exactly its name, next to the moved item (DEF-E17-01,ownItemStillAt(java.lang.String, hudson.model.Item)); and when another item is atoldFullNameagain by the time the event is handled, the records naming it are dropped instead of moved. Records change in the cache first and their write is retried (rewriteCreatedItems(io.jenkins.plugins.batchcontrol.model.Grant, java.util.function.UnaryOperator<java.util.List<java.lang.String>>, java.lang.String)). -
forgetCreatedItem
D-35c: an item recorded as created through an active grant was deleted. The record (and any record of an item below it) is dropped, so an item created later under the same name by someone else confers nothing. -
followItem
D-74: the itemmovedwas renamed or moved fromoldFullNametonewFullName; every active window naming exactlyoldFullNamenow namesnewFullName. Core reports the location change of a folder and then of every item below it, each with its own old and new name, so the windows on the items inside a renamed or moved folder follow too, one event each. Ended windows keep the name they had: they record what was approved.S-39-02, so that no window is left on a name its item no longer has, and none reaches an item nobody approved:
- an active window already naming
newFullName(in any letter case, other than the moved item's own old name) cannot be about the moved item, which only now took that name; it ends first, as on the creation of a new item at its name (its own item vanished without an event, or moved away and its event has not been handled yet), unless its own item is still at exactly its name, next to the moved item (DEF-E17-01,ownItemStillAt(java.lang.String, hudson.model.Item)); - when another item is already at
oldFullNameagain by the time the event is handled (renames whose events interleave), a window naming it can no longer be told to be about the moved item rather than that other item; it ends instead of following; - a window whose file cannot be written with its new name ends (
revokeOne(io.jenkins.plugins.batchcontrol.model.Grant, java.lang.String, java.lang.String, java.lang.String): in memory at once, durably through itsGRANT_REVOKErecord and the retried write) instead of staying on the old name, where an item renamed or moved there later would find it.
Grant.REVOKED_ITEM_NOT_FOLLOWEDas its reason. They are fail-closed: the holder requests the window again. - an active window already naming
-
endWindowsOf
D-74: the itemfullNamewas deleted; every active window naming it, or an item below it, ends: it is revoked byuser, withGrant.REVOKED_ITEM_DELETEDas the reason and aGRANT_REVOKErecord, so it keeps its history. Core reports the deletion before it frees the name, so no item can be created under that name first.S-39-02: the item is remembered as deleted, so a window approved on it whose registration runs after this event, while core has not freed the name yet, still ends (
register(io.jenkins.plugins.batchcontrol.model.Grant, hudson.model.Item)).- Parameters:
user- the user who deleted the item, also when core deleted it as SYSTEM because it lay below a folder that user deleted (SPEC 6: the history names who did what;WindowItemListener)
-
endWindowsOnNewItem
D-74: a new item was created (or copied) underfullName. An active window naming that name cannot be about the new item: its own item disappeared without a deletion event (deleted on disk, then reloaded), or was deleted while the window was being approved. It ends, as for a deletion, so it never applies to the new item. The name is compared as Jenkins looks names up, without regard to letter case (S-39-02): a window under another spelling of the name could otherwise reach the new item through a later rename that only changes the case. A window whose own item is still at exactly its name, next to the new item in a folder that looks its children up by exact name, is about that item and stays (DEF-E17-01,ownItemStillAt(java.lang.String, hudson.model.Item)). -
endWindowsOfMissingItems
D-74: after all items are loaded at startup, ends every active window whose item no longer exists (existsis false for its full name): it was deleted while Jenkins was down, or Jenkins stopped between deleting it and handling the deletion. -
pruneCreatedItems
D-35c, S-09: drops from the created-items lists of active grants every item for whichexistsis false. Called after all items are loaded (startup and reload), so a record of an item deleted on disk while no listener saw it cannot confer anything on an item created later under the same name by someone else. An item that failed to load loses its record too, which only takes permissions away (fail-safe). -
forgetStaleCreatedItem
D-35c, D-74: a new item was created underfullName; a created-item record under that name belongs to an item that disappeared without a deletion event (deleted on disk and reloaded) and is dropped, so it never applies to the new item. The name is compared as Jenkins looks names up, without regard to letter case (S-39-02), except that a record whose own item is still at exactly its name, next to the new item, stays (DEF-E17-01,ownItemStillAt(java.lang.String, hudson.model.Item)). That name only: a copied folder's children are created (and possibly recorded) before the folder's own creation event. -
revoke
Immediately revokes a grant (SPEC item 8: Manage holders only — the web action checks; the service double-checks) and appends aChangeRecord(GRANT_REVOKE).- Returns:
- the revoked grant
- Throws:
IllegalArgumentException- if no such grant existsIllegalStateException- if the grant was already revoked
-
revokeAllActive
public int revokeAllActive()S-15, the kill switch: revokes every grant that is active right now and returns how many were closed. Called when the change-control switch is turned off (seeconfig.BatchControlGlobalConfiguration#setChangeControlEnabled) — turning the switch off has to close the windows that are already open, not merely stop new ones from conferring.Two things this does that
GrantAwareACL's switch check alone does not:- it is durable. The ACL check makes an open window stop conferring while the
switch is off; without the revocation, switching change control back on would bring
every one of those windows back to life for the remainder of its duration (up to
maxGrantMinutes, default 240). A revoked grant never returns —Grant.isActiveAt(java.time.Instant)is false for it for good. - it is visible. Each revocation appends a
ChangeRecord(GRANT_REVOKE)naming the account that flipped the switch, the grantee whose window was closed and the position in the batch, so the audit history says who cut the work off and how much of it there was. A silent mass revocation would be worse than none: the users whose in-flight configuration changes suddenly stop working would have nothing to read.
This is destructive to other people's in-flight work, by design. Whoever turns the switch off cuts off every change currently underway with no warning; that is the trade the owner chose over a switch that leaves windows quietly open. The caller writes its own CONFIG_TOGGLE record before calling this, so the history reads "the switch went off" and then "these windows were closed", in that order.
No permission check of its own, deliberately, and unlike
revoke(String): the caller is a plain configuration setter whose only web entry point is core's/manage/configuresubmission, already gated onOverall/Administer— which impliesBatchControl/Managein any case. Putting a check here would instead impose a permission gate on a setter that JCasC and startup also drive.- Returns:
- the number of active windows that were closed
- it is durable. The ACL check makes an open window stop conferring while the
switch is off; without the revocation, switching change control back on would bring
every one of those windows back to life for the remainder of its duration (up to
-
flushUnsavedEnds
public void flushUnsavedEnds()D-74: writes the ends (and, S-39-02, the created-item records, and, D-75 (2), the changed-item lists) that could not be written so far (called by the periodic work; every grant write and every item event does the same first). -
listAll
Every known grant, active or ended, as the permission checks see it (a copy of the list): an end not yet written to its file is already in it. Screens that list windows read this, not the files, so they agree withlistActive(). -
find
-