Compare commits
3 commits
002a486ecf
...
77792fa4f5
| Author | SHA1 | Date | |
|---|---|---|---|
| 77792fa4f5 | |||
| ac0a4e2fb0 | |||
| 3e0d3d5ebf |
6 changed files with 57 additions and 5 deletions
|
|
@ -164,11 +164,12 @@ The installed `informed-decision-admin` supports local custody operations only:
|
|||
|
||||
```sh
|
||||
informed-decision-admin inspect --db /data/private/review.sqlite
|
||||
informed-decision-admin backup --db /data/private/review.sqlite --output /backup/private/review.sqlite
|
||||
informed-decision-admin backup --db /data/private/review.sqlite --output /data/private/review-YYYYMMDD.sqlite
|
||||
```
|
||||
|
||||
The backup parent must already be owned/private 0700; the destination must not
|
||||
exist. Backup uses SQLite's consistent backup API while the service may be live.
|
||||
exist. The deployment mounts no `/backup` volume; `/data/private` qualifies but
|
||||
shares the PVC, so copy the file off-cluster (`kubectl cp`) for an independent copy. Backup uses SQLite's consistent backup API while the service may be live.
|
||||
Do not copy a running SQLite file while ignoring WAL. Inspection prints counts
|
||||
and schema version, not memo content or credentials. These are privileged
|
||||
operator custody commands, not browser endpoints. An independent backup copy,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:ef6fdd61209863654be3adba070661645a2714e86cb4b7f4e847540291b55f07",
|
||||
"image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:971e88e3c7b68b370f4d7ef14824cc0e19c854b5aeb372e7ec7edbcf2c847b31",
|
||||
"policy": {
|
||||
"origin": "http://flex-auth-informed-decision-sitting.flex-auth.svc.cluster.local:8080",
|
||||
"package": "informed-decision.compact-sitting",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:ef6fdd61209863654be3adba070661645a2714e86cb4b7f4e847540291b55f07",
|
||||
"image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:971e88e3c7b68b370f4d7ef14824cc0e19c854b5aeb372e7ec7edbcf2c847b31",
|
||||
"policy": {
|
||||
"origin": "http://flex-auth-informed-decision-t03.flex-auth.svc.cluster.local:8080",
|
||||
"package": "informed-decision.t03-review",
|
||||
|
|
|
|||
30
docs/evidence/2026-09-21-decision-overview-image.json
Normal file
30
docs/evidence/2026-09-21-decision-overview-image.json
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"task": "INFD-WP-0003",
|
||||
"source_commit": "3e0d3d5",
|
||||
"change": "Signed-in home page lists the reviewer's decision memos grouped as needs attention, open, accepted, declined, returned, closed or not available, with fallback to the memo form if listing fails. UI_RELEASE unchanged (informed-decision@0.2.0); store schema unchanged (v2); no new write path.",
|
||||
"validation": "433 tests passed with actual Approval Engine, Audit Core and Flex Auth; Chromium harness 13/13; container smoke 11/11; Trivy 0.74.0 HIGH/CRITICAL: 0 findings.",
|
||||
"image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:971e88e3c7b68b370f4d7ef14824cc0e19c854b5aeb372e7ec7edbcf2c847b31",
|
||||
"previous_live_image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:ef6fdd61209863654be3adba070661645a2714e86cb4b7f4e847540291b55f07",
|
||||
"published": true,
|
||||
"rolled_out": true,
|
||||
"remaining": "Human sign-in view of the overview not yet observed by the agent.",
|
||||
"rollout": {
|
||||
"by": "operator",
|
||||
"strategy": "Recreate via kubectl set image",
|
||||
"pre_rollout_inspect": {
|
||||
"schema_version": 2,
|
||||
"outbox": {
|
||||
"delivered": 50
|
||||
},
|
||||
"submissions": {
|
||||
"confirmed": 7
|
||||
}
|
||||
},
|
||||
"pre_rollout_backup": "/data/private/review-20260921-pre-overview.sqlite (same PVC; consistent_snapshot true)",
|
||||
"post_rollout": {
|
||||
"ready_replicas": 1,
|
||||
"healthz": "ok",
|
||||
"readyz": "ready"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -188,7 +188,7 @@ class App:
|
|||
if method == "GET" and path == "/":
|
||||
if session:
|
||||
content = (f"<p>Signed in as {html.escape(session.subject)}.</p>"
|
||||
+ (overview_section(self.review.overview(session)) if self.review is not None else '')
|
||||
+ (self._overview(session) if self.review is not None else '')
|
||||
+ ('<h2>Open a decision review</h2><p>Enter the memo identifier supplied with your review request.</p>'
|
||||
'<form method="get" action="/review"><label>Memo identifier <input name="memo_id" required maxlength="256"></label>'
|
||||
'<button type="submit">Open review</button></form>' if self.review is not None else
|
||||
|
|
@ -201,6 +201,19 @@ class App:
|
|||
return 200, document("Informed Decision", content, session.subject if session else None), "text/html", []
|
||||
return 404, "Not found.", "text/plain", []
|
||||
|
||||
def _overview(self, session):
|
||||
# The overview is orientation only. Its failure must never take the
|
||||
# memo form, sign-out or an unresolved-entry recovery path with it.
|
||||
try:
|
||||
return overview_section(self.review.overview(session))
|
||||
except ReviewError as exc:
|
||||
if exc.code == "session_expired":
|
||||
raise
|
||||
except (PolicyError, ApprovalEngineError, StoreError, sqlite3.Error, ValueError, KeyError, TypeError):
|
||||
pass
|
||||
return ('<h1>Your decisions</h1><div class="notice warning" role="status">Your decisions could not be '
|
||||
'listed right now. You can still open a review by its memo identifier.</div>')
|
||||
|
||||
def _form(self, environ, session):
|
||||
if environ.get("HTTP_ORIGIN") != ORIGIN:
|
||||
raise ReviewError(403, "invalid_form")
|
||||
|
|
|
|||
|
|
@ -407,3 +407,11 @@ def test_home_without_session_shows_sign_in_only(review):
|
|||
r=call(app,'/')
|
||||
assert 'Sign in with KeyCape' in r['body'] and 'Your decisions' not in r['body']
|
||||
assert controller.store.policy_observations()==[]
|
||||
|
||||
|
||||
def test_home_keeps_the_memo_form_when_the_overview_fails(review,monkeypatch):
|
||||
controller,session,app,*_=review
|
||||
def broken(subject):raise sqlite3.OperationalError('disk')
|
||||
monkeypatch.setattr(controller.store,'memos_for',broken)
|
||||
r=home(review)
|
||||
assert r['status']==200 and 'could not be listed right now' in r['body'] and 'Open a decision review' in r['body']
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue