refactor(skills): consolidate managed skill library 94 -> 25
The managed-skill library was regenerated: 94 narrow per-incident skills
replaced by 25 broader ones (radiance-*, llamacpp-*, homepage-*, fleet/
endpoint ops). Git renders this as mass delete + mass add because whole
directories changed name; old content stays in history at 12c5e88.
Surface check: the 25 on disk are exactly the skills the harness advertises
this session.
This commit is contained in:
1 parent
94c71a016f
commit
a34322aeb0
119 files changed
+740
-5816
No files matched your search
@@ -0,0 +1,42 @@
|
||||
---
|
||||
name: authentik-provision-fleet-user
|
||||
description: "Provision or audit an Authentik user on Dankclaw (auth.franksdank.cloud): ak shell ORM drive, group set, behavioral login verify, stale-claim caveat."
|
||||
---
|
||||
|
||||
# Provision an Authentik user on Dankclaw
|
||||
|
||||
Source of truth: `serverAppConfigs-docs/Infrastructure/Authentik.md` ("User provisioning playbook"). Authentik objects are NOT repo-managed — no deploy, no file edits.
|
||||
|
||||
1. Inspect first, mirror the newest human user's groups:
|
||||
```bash
|
||||
ssh dankclaw 'podman exec -i authentik-server ak shell' <<'EOF' 2>&1 | sed -n '/objects imported/,$p'
|
||||
from authentik.core.models import User, Group
|
||||
for u in User.objects.all().order_by("username"):
|
||||
print(u.username, u.email, sorted(u.groups.values_list("name", flat=True)))
|
||||
print(sorted(Group.objects.values_list("name", flat=True)))
|
||||
EOF
|
||||
```
|
||||
2. Create (idempotent guard; password goes in the heredoc = stdin, never argv, so it never lands in `ps`):
|
||||
```python
|
||||
from authentik.core.models import User, Group
|
||||
u = User.objects.filter(username="X").first()
|
||||
if not u:
|
||||
u = User(username="X", email="X@franksdank.cloud", name="X", is_active=True)
|
||||
u.set_password("...")
|
||||
u.save()
|
||||
for g in ("Non-Admin Users", "jellyfin_users", "openwebui_users"): # human-user precedent: ridley
|
||||
u.groups.add(Group.objects.get(name=g))
|
||||
```
|
||||
3. Verify through the exact PasswordStage code path:
|
||||
```python
|
||||
from django.contrib.auth import authenticate
|
||||
assert authenticate(request=None, username="X", password="...")
|
||||
assert authenticate(request=None, username="X", password="nope") is None
|
||||
```
|
||||
|
||||
## Rules
|
||||
- No `User.create_user`; `is_superuser` is a group-derived property, not a constructor kwarg (raises `TypeError`). `path` defaults to `users`.
|
||||
- Guarded-vhost access = any authenticated user (all proxy providers use implicit-consent); groups are consumed downstream: `homepage-admins` (Caddy `/admin` header gate), `openwebui_users`/`_admins` (roles claim), `jellyfin_users`/`_admins` (LDAP outpost). EXCLUDE admin groups from a plain user; ask before granting `homepage-admins`.
|
||||
- Group add after a login → Caddy RBAC can 403 on the outpost's cached claims; purge that user's rows: `DELETE FROM authentik_providers_proxy_proxysession WHERE session_data->'claims'->>'preferred_username' = 'X';` (in the `authentik-postgres` container) — next visit re-authorizes silently.
|
||||
- Jellyfin visibility rides the LDAP outpost cache; expect a lag.
|
||||
- Look up flows by slug, not name. Do not rotate `AUTHENTIK_SECRET_KEY` to fix claim issues.
|
||||
Reference in new issue
Block a user