feat: complete the group model (god_admin, site groups, aggregates), enforce naming, fix docs 500s + status dots (v1.26.0)
- seed god_admin + nest into app_super_admin; auto-provision site groups (S_super_admin, S_hosts_*/S_apps_* aggregates, S_everyone) on site create + self-heal on Directory load - map service resources to the app kind (site_local_app_<slug>_*); nest per-resource groups into site aggregates (physical inheritance lattice) - enforce the group naming convention server-side on POST /groups; surface god_admin + site groups on the site resource modal - fix in-app /docs/<slug> 500s (Dockerfile never copied docs/); serve doc images at /docs/images - fix Directory status dots (neutral grey when agent endpoint unreachable); align Profile/API cards full-width - group resolver: keep the site slug verbatim (site_local not re-slugified) - bump to 1.26.0
This commit is contained in:
+14
-5
@@ -42,25 +42,31 @@ function assertKind(kind) {
|
||||
}
|
||||
|
||||
// {site}_host_<slug>_<level> / {site}_app_<slug>_<level>
|
||||
//
|
||||
// `site` is the site resource's slug verbatim (e.g. `site_local`, or a clean
|
||||
// `main-office`), NOT slugified: directory resource slugs may legitimately carry
|
||||
// a kind prefix (`site_local`, `host_theta-env`), and re-slugifying those would
|
||||
// corrupt the delimiter (site_local -> site-local). Callers pass already-
|
||||
// normalized site + kind-stripped resource slugs.
|
||||
function resourceGroupCns(site, kind, slug, level) {
|
||||
assertKind(kind);
|
||||
return `${slugify(site)}_${kind}_${slugify(slug)}_${level}`;
|
||||
return `${site}_${kind}_${slugify(slug)}_${level}`;
|
||||
}
|
||||
|
||||
// {site}_hosts_<level> / {site}_apps_<level> (plural kind — the aggregate).
|
||||
function aggregateGroupCns(site, kind, level) {
|
||||
assertKind(kind);
|
||||
return `${slugify(site)}_${kind}s_${level}`;
|
||||
return `${site}_${kind}s_${level}`;
|
||||
}
|
||||
|
||||
// {site}_super_admin
|
||||
function siteSuperAdminCns(site) {
|
||||
return `${slugify(site)}_super_admin`;
|
||||
return `${site}_super_admin`;
|
||||
}
|
||||
|
||||
// {site}_everyone
|
||||
function siteEveryoneCns(site) {
|
||||
return `${slugify(site)}_everyone`;
|
||||
return `${site}_everyone`;
|
||||
}
|
||||
|
||||
// True if `level` is a known admin/access level (not an opaque capability).
|
||||
@@ -87,7 +93,10 @@ function levelGrants(level, wanted) {
|
||||
// granted groups (see permission.onResource). This keeps the function pure over
|
||||
// the user's membership only.
|
||||
function hasPermission(memberOf, resource, level) {
|
||||
const site = slugify(resource && resource.site);
|
||||
// `site` is used verbatim (resource slugs may carry a kind prefix, e.g.
|
||||
// `site_local`) -- see resourceGroupCns; the resource `slug` is expected
|
||||
// kind-stripped and already-normalized, so slugify() is a harmless guard.
|
||||
const site = resource && resource.site;
|
||||
const kind = resource && resource.kind;
|
||||
const slug = slugify(resource && resource.slug);
|
||||
const set = new Set(memberOf || []);
|
||||
|
||||
Reference in New Issue
Block a user