Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Make access edits and approvals survive a concurrent change

62b59a76f9064a58a45d0997f6889d2a7f6265e7 · Keenan Nemetz · 12d ago · parent 78cd3437

Make access edits and approvals survive a concurrent change

Access rules were one row, and every editor read it, changed a field, and
wrote the whole document back with no version check. Two people on the
page at once silently overwrote each other, and the specific case that
mattered was worse than a lost edit: a repository admin's stale settings
save could restore a role an instance admin had just revoked.

The row now carries a revision, and a rule set read through the store
carries the revision it was read at. Writing it back is a
compare-and-swap: if the row moved, the write is refused with ErrConflict
instead of undoing the other change. A rule set built from scratch is a
create and refuses if a row appeared meanwhile, so no stale document can
replace a live one. Existing instances get the column added on open.

On top of that, the operations that own one field apply it to the row as
it is now (Store.Update, retried against a moving row):

  - the repository Settings page writes only the visibility. It no longer
    rewrites entries, runners or the approval policy, so an instance
    admin's revocation survives a page that was loaded before it.
  - adding one account writes that one entry.
  - the access form changes only the rows it rendered; an entry or a
    runners-list membership added while the page was open is kept.

Approvals and runners are also bound to current standing. An approval
counts only while its author is an active account that still holds
maintain or admin on the repository, filtered in FindApprovedMatch and
counted the same way on the request page, so the page cannot promise a
merge the gate then refuses. ACL.CanReport refuses a retired account even
while its name is in the runners list; the row outlives the account, so
membership alone would let a revoked account keep vouching for builds and
leasing jobs. The roster's Active predicate is attached by the store, the
same way the instance role already was, in both the server and the hook
process.

Tests: a stale whole-document write is refused and cannot restore a
revoked role; concurrent field-scoped updates all land; Update reports
the row as it is now; a retired account stops counting as an approver and
as a runner; a demoted maintainer's approval no longer lands a change; a
settings save leaves entries, runners, approval policy and protection
alone; a retired runner's record push is refused.

docs/accounts-and-access.md +10−1

@@ -161,6 +161,13 @@ specific accounts.
161 161 | `maintain` | Everything the contribute role can do, plus push shared branches, triage issues, and approve change requests |
162 162 | `admin` | Everything a maintainer can do, plus manage access, push protected branches, override locks, and repair metadata |
163 163
164 Rules are edited with a compare-and-swap. A page or a command that read the rules
165 before somebody else changed them is refused rather than allowed to write its copy
166 back, so an instance admin revoking a role cannot be undone by a repository admin
167 who still has the older page open. The operations that own one field — the
168 visibility toggle, adding one account, one runners entry — re-read the row and
169 apply only that field, so an unrelated concurrent change is kept.
170
164 171 A new repository is private. Its default role is `none`, and its owner is an
165 172 admin. Private repositories return `404` to anonymous visitors, so people cannot
166 173 tell whether they exist. An instance-wide `read`, `contribute`, or `maintain`
@@ -220,7 +227,9 @@ vole admin acl runners add demo ci-runner-1
220 227 updated; `checks disable` allows approvals alone to land it.
221 228 - `runners` manages the accounts whose CI results this repository trusts. It uses
222 229 the same `list`, `add`, `remove`, `set`, and `clear` verbs as `protect`.
223 Admins always count. See
230 Admins always count. A retired account stops counting even while its name is
231 still in the list: the ACL row outlives the account, so membership alone is not
232 a grant that lasts. See
224 233 [Runners](runner.md#who-can-run-jobs-and-report-results).
225 234
226 235 ## Contributors and their branches