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/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

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

Add instance-wide roles and refine access UI

5b814e9958090cfd1fa826efb2d375bf613547c1 · Keenan Nemetz · 14d ago · parent 9579c1f9

Add instance-wide roles and refine access UI

Instance roles now live on accounts, apply to public repositories, and the Admin role is the unified instance-admin permission with access to every repository. Repository ACLs can raise an instance role but not lower it.

Adds role assignment to the users UI and CLI, open-registration role config, a reusable role picker, and separates adding a repository account from saving access rules.

server/web/static/vole.css +56

@@ -1558,6 +1558,62 @@ details[open] > summary .tree-chevron { transform: rotate(90deg); }
1558 1558 .acl-check { display: flex; align-items: center; gap: 6px; }
1559 1559 .acl-check input[type="checkbox"] { width: auto; margin: 0; }
1560 1560 table.acl select { min-width: 9rem; }
1561 .role-options { border: 0; padding: 0; margin: 0; min-width: 0; }
1562 .role-options legend {
1563 padding: 0;
1564 margin: 0 0 8px;
1565 color: var(--fg);
1566 font-size: 13px;
1567 font-weight: 600;
1568 }
1569 .role-options > p { margin: 0 0 10px; }
1570 .role-option {
1571 display: flex;
1572 align-items: baseline;
1573 gap: 7px;
1574 margin: 5px 0;
1575 padding: 7px 10px;
1576 border: 1px solid var(--border);
1577 border-radius: var(--radius);
1578 color: var(--fg);
1579 font-size: 13px;
1580 cursor: pointer;
1581 }
1582 .role-option:hover { border-color: var(--border-strong); background: var(--bg-raised); }
1583 .role-option:has(input[type="radio"]:checked) {
1584 border-color: var(--accent);
1585 background: var(--accent-soft);
1586 }
1587 .role-option input[type="radio"] {
1588 display: block;
1589 flex: 0 0 auto;
1590 width: auto;
1591 margin: 0;
1592 accent-color: var(--accent);
1593 }
1594 .role-option .role-name { font-weight: 600; }
1595 .role-option .role-desc { color: var(--fg-muted); font-size: 12px; line-height: 1.45; }
1596 .role-options.compact { display: flex; flex-wrap: wrap; gap: 4px 12px; }
1597 .role-options.compact legend { display: none; }
1598 .role-options.compact .role-option {
1599 display: inline-flex;
1600 align-items: center;
1601 gap: 5px;
1602 margin: 0;
1603 padding: 0;
1604 border: 0;
1605 border-radius: 0;
1606 background: none;
1607 font-size: 12px;
1608 }
1609 .role-options.compact .role-option:hover { background: none; }
1610 .role-options.compact .role-option:has(input[type="radio"]:checked) {
1611 border: 0;
1612 background: none;
1613 }
1614 .role-options.compact .role-option:has(input[type="radio"]:checked) .role-name { color: var(--accent); }
1615 .role-options.compact .role-desc { display: none; }
1616 .role-options.compact input[type="radio"] { margin: 0; }
1561 1617 .form-card { margin: 0; }
1562 1618 .form-actions {
1563 1619 display: flex;