Three fixes:
1. gql() default vars '${2:-{}}' — bash parsed first '}' as closing the
parameter expansion, appending a stray '}' to every caller's vars.
Fixed by storing '{}' in a local variable first.
2. make_vars() — add VAR_INT_KEYS support so groupId is emitted as a
JSON integer (Int!) rather than a string, matching LLDAP's schema.
3. Password setting — LLDAP has no GraphQL mutation for admin password
reset. Replace the broken resetUserPasswordFromAdmin mutation with
an RFC 3062 LDAP Password Modify operation via kubectl port-forward
to the in-cluster LLDAP service, using ldap3.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
--test derives the password from the display name (spaces → hyphens, append -Pwd),
e.g. "Test User" → "Test-User-Pwd". Skips the interactive prompt.
Useful for provisioning test accounts in a non-interactive flow.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pass GraphQL query/variables and group names via environment variables
to python3 instead of shell argument interpolation. Prevents breakage
when display names, emails, or passwords contain quotes or spaces.
Also adds --admin flag support and interactive password prompt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Creates a user in LLDAP via GraphQL, adds them to net-kingdom-users,
optionally net-kingdom-admins (--admin flag), and sets a password interactively.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Once any admin policy exists, PI enforces it for all admins. Without an
explicit policy, pi-admin is locked out of the REST API after trigger-admin-rights
is created. Add pi-admin-all-rights (scope=admin, action=*) via pi-manage
(in-pod) as step 5, before the REST-based trigger-admin-rights step.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PI_NO_RESPONSE_SIGN=True works around Werkzeug 3.x crash where request.json
raises BadRequest on GET requests with empty bodies (sign_response path).
Rate limit raised from 20/5 to 200/100 req/min to allow the AngularJS UI's
burst of ~50 parallel static asset requests on each page load without being
throttled by Traefik. TODO: split tight /auth+/validate vs loose /static limits.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Added allow-traefik-to-acme-solver NetworkPolicy to sso and mfa namespaces.
The default-deny-all policy was blocking HTTP-01 challenge traffic from Traefik
to the cert-manager solver pods, causing all TLS certs to stay pending (502).
Workplan NK-WP-0003 updated: T02, T03, T04, T05, T06, T07, T08a all done on
RAILIANCE01 as of 2026-03-25. T08 (e2e auth test) is now unblocked.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All 3 KeyCape test packages pass (migration, negative, profile).
DNS resolves for all 4 subdomains; Go 1.22.10 available at ~/go/bin/go.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- deployment.yaml: image → 92.205.130.254:32166/coulomb/key-cape:latest
(Gitea OCI registry, delivered by KEY-WP-0002; imagePullPolicy: Always)
- k3s insecure registry hosts.toml: fixed server endpoint to http:// so
containerd does not attempt HTTPS against the plain-HTTP Gitea NodePort
- create-secrets.sh: add demo-app OIDC client (required for KeyCape to
start; also needed for T08 acceptance tests)
- keycape-config Secret updated in-place (no re-bootstrap needed)
KeyCape pod 1/1 Running; /healthz OK; OIDC discovery live at
https://kc.coulomb.social/.well-known/openid-configuration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pod Running with correct image and config. enckey, audit keys, pi-admin,
trigger-admin all created via agent bootstrap (NK-WP-0005).
Remaining: TLS cert + trigger-admin policy via WebUI.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- creds-bootstrap-agent.sh: skip Phase 3 if all secrets already applied
(avoids CNPG SSL connection drops from repeated reconciliation)
- creds-bootstrap-agent.sh: wait for rollout to complete after restart
before running enckey/admin bootstrap (fixes race with old pod)
- creds-bootstrap-agent.sh: only restart privacyIDEA when Phase 3 ran
- create-pi-token.sh: use env-var + retry for token fetch (no heredoc
stdin; handles transient 500 from idle connection pool)
- create-pi-token.sh: create keycape-pi-token K8s Secret after fetching
- creds-verify.sh: map keycape-pi-token to secrets_applied.keycape
(not pi_admin_created, which caused spurious Phase 5 re-runs)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
gpappsoft entrypoint requires PI_ADDRESS and PI_PORT env vars to build
the gunicorn bind argument. Without them the container crashes immediately.
/token/ returns 401 for unauthenticated GET requests so the httpGet
readiness probe was permanently failing. Switch to tcpSocket to match
the startup and liveness probes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
gpappsoft image sets PRIVACYIDEA_CONFIGFILE=/privacyidea/etc/pi.cfg
internally, causing it to ignore our mounted configmap at
/etc/privacyidea/pi.cfg and fall back to SQLite.
Override the env var so the entrypoint reads our pi.cfg, which points
to PostgreSQL via PI_SQLALCHEMY_DATABASE_URI from the secret.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
privacyidea/privacyidea:3.12 and privacyidea/otpserver:3.12.2 do not
exist on Docker Hub. Correct image is ghcr.io/gpappsoft/privacyidea-docker:3.12.2
which listens on port 8080.
Update all port references: deployment, service, ingress, netpol-mfa,
netpol-sso (keycape→privacyIDEA egress rule).
Also: creds-bootstrap-agent.sh — restart privacyIDEA deployment after
applying new secrets so the pod picks up updated env vars.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- NK-WP-0003 T08: replace hardcoded /home/worsch/key-cape with
$(git rev-parse --show-toplevel)/../key-cape so acceptance tests
run correctly on any machine
- NK-WP-0005 T04: create .claude/commands/creds-init.md — the
autonomous credential bootstrap skill (reads creds-state.yaml,
resumes from current phase, honours emergency bundle gate)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
NK-WP-0005: mark all tasks done, status → done
NK-WP-0003: T01 marked done (NK-WP-0004/0005 complete); pre-conditions
updated; done criteria reflect agent-bootstrap model (no KeePassXC)
NK-WP-0001: status → deferred; T05-T08 (Keycloak) deferred indefinitely;
superseded_by: NK-WP-0003 added
Active work path is now NK-WP-0003 T02-T09.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the human-as-operator model from NK-WP-0004 with full agent
automation. Agent generates, encrypts (SOPS), injects into cluster,
and delivers a single emergency bundle (age key + break-glass passwords).
Human only stores that bundle in their personal password manager.
KeePassXC removed from operational path. creds-state.yaml redesigned
with agent_mode and emergency_bundle_delivered gate. Standard to be
updated to v0.2 (T07).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All 7 tasks were implemented in c10d7d2 but fix-consistency on the
workstation reverted all statuses to todo (CUST-WP-0026 regression bug).
Corrected all task blocks to status: done and workplan status to done.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>