Prepare persistent personal app release and guarded OIDC repair
Some checks failed
Use-case regression gate / usecase-regressions (push) Has been cancelled
Some checks failed
Use-case regression gate / usecase-regressions (push) Has been cancelled
Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a10e2d-a5ef-7e92-b03d-b1694e915680
This commit is contained in:
parent
a1989f19db
commit
ac7bac1852
7 changed files with 164 additions and 36 deletions
17
.dockerignore
Normal file
17
.dockerignore
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
.git
|
||||||
|
.venv
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
.auth
|
||||||
|
var
|
||||||
|
staticfiles
|
||||||
|
db.sqlite3
|
||||||
|
**/__pycache__
|
||||||
|
**/*.pyc
|
||||||
|
.pytest_cache
|
||||||
|
.ruff_cache
|
||||||
|
scripts/node_modules
|
||||||
|
tests
|
||||||
|
docs
|
||||||
|
history
|
||||||
|
workplans
|
||||||
|
|
@ -38,7 +38,8 @@ COPY manage.py pyproject.toml ./
|
||||||
COPY coulomb_social ./coulomb_social
|
COPY coulomb_social ./coulomb_social
|
||||||
COPY scripts/docker-entrypoint.sh /app/docker-entrypoint.sh
|
COPY scripts/docker-entrypoint.sh /app/docker-entrypoint.sh
|
||||||
|
|
||||||
RUN chmod +x /app/docker-entrypoint.sh \
|
RUN python manage.py collectstatic --noinput \
|
||||||
|
&& chmod +x /app/docker-entrypoint.sh \
|
||||||
&& chown -R appuser:appuser /app
|
&& chown -R appuser:appuser /app
|
||||||
USER appuser
|
USER appuser
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,19 +29,13 @@ X-Verified-Oidc-Claims: {"iss","sub","tenant","principal_type","aud",...}
|
||||||
plus `coulomb-social`. Trust is the proxy secret; claims were verified by
|
plus `coulomb-social`. Trust is the proxy secret; claims were verified by
|
||||||
KeyCape OIDC at the app edge.
|
KeyCape OIDC at the app edge.
|
||||||
|
|
||||||
### Operator: enable HTTP mode locally
|
### Governed credential configuration
|
||||||
|
|
||||||
```bash
|
Live HTTP mode already uses mounted runtime credential references. Do not
|
||||||
# secret never printed to shell history if you use process substitution carefully
|
extract the proxy secret with kubectl/jsonpath or print it into shell/chat.
|
||||||
export USER_ENGINE_BASE_URL=https://users.92-205-62-239.nip.io
|
For a new credential need, run `warden route find "user-engine trusted proxy credential" --json`
|
||||||
export USER_ENGINE_PROXY_SECRET="$(kubectl -n user-engine get secret user-engine-runtime \
|
and follow the owning OpenBao/platform lane. Interactive personal login belongs
|
||||||
-o jsonpath='{.data.proxy-secret}' | base64 -d)"
|
to KeyCape/NetKingdom; it does not require retrieving this server credential.
|
||||||
export USER_ENGINE_EXPECTED_AUDIENCE=user-engine-portal
|
|
||||||
# then OIDC or dev-login
|
|
||||||
```
|
|
||||||
|
|
||||||
OpenBao lane for the proxy secret (future): document under railiance-platform
|
|
||||||
workload KV; until then kubectl-sourced secret is operator-only on the workstation.
|
|
||||||
|
|
||||||
## Profile attributes (shell only)
|
## Profile attributes (shell only)
|
||||||
|
|
||||||
|
|
|
||||||
47
scripts/keycape-client-repair.py
Normal file
47
scripts/keycape-client-repair.py
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Restore the historical public client through NetKingdom's guarded lane.
|
||||||
|
|
||||||
|
Inspection is read-only. Apply requires exact founder approval and a fresh
|
||||||
|
UID/resource-version receipt. Secret values stay inside the owner helper.
|
||||||
|
"""
|
||||||
|
import importlib.util
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
from types import SimpleNamespace
|
||||||
|
|
||||||
|
|
||||||
|
def load(name, path):
|
||||||
|
spec = importlib.util.spec_from_file_location(name, path)
|
||||||
|
result = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def configure(owner_root):
|
||||||
|
rollout = load("keycape_guarded_rollout", owner_root / "portal-client-rollout.py")
|
||||||
|
historical = load("coulomb_registration", owner_root / "register-coulomb-social.py")
|
||||||
|
original = rollout.replacement
|
||||||
|
rollout.portal = SimpleNamespace(CLIENT_ID=historical.CLIENT_ID, CLIENT=historical.CLIENT)
|
||||||
|
|
||||||
|
def replacement(secret):
|
||||||
|
_, config, _ = rollout.pin.issuer_document(secret)
|
||||||
|
for client in config.get("clients", []):
|
||||||
|
if client.get("clientId") == historical.CLIENT_ID:
|
||||||
|
rollout.require(client == historical.CLIENT, "existing_registration_differs")
|
||||||
|
return original(secret)
|
||||||
|
|
||||||
|
rollout.replacement = replacement
|
||||||
|
return rollout
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
owner_root = Path(os.environ.get(
|
||||||
|
"NET_KINGDOM_KEYCAPE_DIR",
|
||||||
|
str(Path.home() / "net-kingdom/sso-mfa/k8s/keycape"),
|
||||||
|
))
|
||||||
|
helper = configure(owner_root)
|
||||||
|
except Exception:
|
||||||
|
print('{"status":"failed","reason":"owner_helper_unavailable"}')
|
||||||
|
raise SystemExit(1)
|
||||||
|
raise SystemExit(helper.main())
|
||||||
|
|
@ -1,26 +1,8 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Register this app's OIDC client on live KeyCape (kc.coulomb.social).
|
# Inspect by default; explicit dry-run/apply use guarded owner receipts.
|
||||||
# Delegates to net-kingdom/sso-mfa/k8s/keycape/register-coulomb-social.sh
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
NK_SCRIPT="${NET_KINGDOM_KEYCAPE_DIR:-$HOME/net-kingdom/sso-mfa/k8s/keycape}/register-coulomb-social.sh"
|
if [[ $# -eq 0 ]]; then
|
||||||
|
set -- inspect
|
||||||
if [[ ! -x "$NK_SCRIPT" && ! -f "$NK_SCRIPT" ]]; then
|
|
||||||
echo "ERROR: KeyCape register script not found: $NK_SCRIPT" >&2
|
|
||||||
echo "Clone net-kingdom or set NET_KINGDOM_KEYCAPE_DIR." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
exec python3 "$ROOT/scripts/keycape-client-repair.py" "$@"
|
||||||
chmod +x "$NK_SCRIPT" 2>/dev/null || true
|
|
||||||
bash "$NK_SCRIPT"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "Next: export OIDC settings and restart the app:"
|
|
||||||
echo " export OIDC_ENABLED=true"
|
|
||||||
echo " export OIDC_ISSUER=https://kc.coulomb.social"
|
|
||||||
echo " export OIDC_CLIENT_ID=coulomb-social"
|
|
||||||
echo " export OIDC_REDIRECT_URI=http://127.0.0.1:8008/auth/callback/"
|
|
||||||
echo " # no client secret — public + PKCE"
|
|
||||||
echo " make run"
|
|
||||||
echo "Docs: $ROOT/docs/identity/oidc-client.md"
|
|
||||||
|
|
|
||||||
49
scripts/test_keycape_client_repair.py
Normal file
49
scripts/test_keycape_client_repair.py
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
"""Synthetic owner-lane checks; run with python3 scripts/test_keycape_client_repair.py."""
|
||||||
|
import base64
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from importlib.machinery import SourceFileLoader
|
||||||
|
|
||||||
|
adapter = SourceFileLoader("csoc_repair", str(Path(__file__).with_name("keycape-client-repair.py"))).load_module()
|
||||||
|
|
||||||
|
|
||||||
|
class RepairTests(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.rollout = adapter.configure(Path.home() / "net-kingdom/sso-mfa/k8s/keycape")
|
||||||
|
|
||||||
|
def fixture(self, clients):
|
||||||
|
raw = ("# keep comment\nauthelia:\n issuer: https://auth.example.invalid\n"
|
||||||
|
" clientSecret: synthetic-marker\nclients:\n" +
|
||||||
|
yaml.safe_dump(json.loads(json.dumps(clients)), sort_keys=False) + "tokenLifetime: 15m\n")
|
||||||
|
return {"data": {"config.yaml": base64.b64encode(raw.encode()).decode(),
|
||||||
|
"key.pem": "synthetic-key"}}, raw
|
||||||
|
|
||||||
|
def test_insert_preserves_bytes_and_is_idempotent(self):
|
||||||
|
secret, raw = self.fixture([{"clientId": "existing", "clientType": "public"}])
|
||||||
|
encoded, changed = self.rollout.replacement(secret)
|
||||||
|
updated = base64.b64decode(encoded).decode()
|
||||||
|
self.assertTrue(changed)
|
||||||
|
self.assertTrue(updated.startswith(raw[:raw.index("tokenLifetime:")]))
|
||||||
|
self.assertTrue(updated.endswith("tokenLifetime: 15m\n"))
|
||||||
|
expected = yaml.safe_load(raw)
|
||||||
|
expected["clients"].append(self.rollout.portal.CLIENT)
|
||||||
|
self.assertEqual(yaml.safe_load(updated), expected)
|
||||||
|
self.assertEqual(secret["data"]["key.pem"], "synthetic-key")
|
||||||
|
secret["data"]["config.yaml"] = encoded
|
||||||
|
self.assertEqual(self.rollout.replacement(secret), (encoded, False))
|
||||||
|
|
||||||
|
def test_refuses_different_or_duplicate_registration(self):
|
||||||
|
client = self.rollout.portal.CLIENT
|
||||||
|
for clients in [[dict(client, redirectUris=["https://other.invalid/callback"])],
|
||||||
|
[dict(client, allowedScopes=["openid", "admin"])],
|
||||||
|
[client, client]]:
|
||||||
|
with self.subTest(clients=clients), self.assertRaises(self.rollout.Refused):
|
||||||
|
self.rollout.replacement(self.fixture(clients)[0])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
|
|
@ -66,7 +66,7 @@ an instruction to bulk-move every space before the first user review.
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: CSOC-WP-0008-T01
|
id: CSOC-WP-0008-T01
|
||||||
status: wait
|
status: progress
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "6adce69f-9011-5ada-a920-b2228aa15218"
|
state_hub_task_id: "6adce69f-9011-5ada-a920-b2228aa15218"
|
||||||
```
|
```
|
||||||
|
|
@ -266,3 +266,41 @@ clipboard and blocked/manual fallback pass Chromium checks with synthetic data.
|
||||||
Full application suite: 87 passed; new test Ruff clean. Real latest protocol
|
Full application suite: 87 passed; new test Ruff clean. Real latest protocol
|
||||||
reconciliation and actual mail-client/user review remain T03/T09, not completed
|
reconciliation and actual mail-client/user review remain T03/T09, not completed
|
||||||
by these tests. No live deploy, private-data import or mail sending performed.
|
by these tests. No live deploy, private-data import or mail sending performed.
|
||||||
|
|
||||||
|
## Live orientation and personal account — 2026-10-06
|
||||||
|
|
||||||
|
Fresh checks confirm a healthy 1/1 coulomb-social Helm workload on railiance01
|
||||||
|
(92.205.62.239), image 7fcd0cf, revision 9. app.coulomb.social landing and health
|
||||||
|
return 200; KeyCape discovery is live. No content PVC/CONTENT_ROOT exists in
|
||||||
|
that old release. One live Member links the user-selected tegwick identity to
|
||||||
|
KeyCape and tenant:coulomb; one demo space exists. No new password/account is
|
||||||
|
needed. The user tried sign-in and received invalid_profile_usage / unknown
|
||||||
|
client_id. Guarded issuer inspection confirms the coulomb-social client is absent;
|
||||||
|
the stored Member and healthy discovery did not prove interactive login worked.
|
||||||
|
|
||||||
|
T01 now progresses by preparing the latest tested app image with collected
|
||||||
|
static assets and an owning-chart persistent CONTENT_ROOT upgrade. Single-writer
|
||||||
|
Recreate avoids concurrent filesystem writers and rolling CPU surge. Exact live
|
||||||
|
change approval follows the prepared diff/dry-run and immutable image receipt.
|
||||||
|
Node CPU requests observed 3455m/4000m; disk has 123G available.
|
||||||
|
No deployment or credential change was made by these read-only checks.
|
||||||
|
|
||||||
|
## T11 — Restore personal OIDC sign-in
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: CSOC-WP-0008-T11
|
||||||
|
status: progress
|
||||||
|
priority: high
|
||||||
|
```
|
||||||
|
|
||||||
|
Restore the historical NetKingdom public coulomb-social authorization-code/PKCE
|
||||||
|
client through the owning guarded helper; refuse differing existing registrations,
|
||||||
|
preserve unrelated configuration bytes and Secret data, pin cluster identity and
|
||||||
|
Secret UID/resourceVersion. Inspection and server dry-run passed on 2026-10-06;
|
||||||
|
no live change made. Existing historical ordinary AAL1 behavior (mfaRequired:
|
||||||
|
false) is explicit in the review packet; shared issuer restart requires exact
|
||||||
|
founder approval. User tegwick must then confirm interactive login. Do not mark
|
||||||
|
this task done on an HTTP redirect or discovery-only check.
|
||||||
|
|
||||||
|
Knowledge receipt: emergent-security 0.2.6 identity, verified-files,
|
||||||
|
orientation-only; digest 8d1d6a9d4d07fec7b619618de7dfe2be2254c1790f85f4198c7fe19db9751c02.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue