Isolate tenant readback cache and prepare verified runtime release
Some checks failed
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 2s
Build and Publish Container Image / build-and-push (push) Successful in 1m33s
Account journey acceptance / journeys (push) Failing after 7s

Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
This commit is contained in:
tegwick 2026-10-11 01:58:45 +02:00
parent c460e2b0df
commit 1bb7cacc98
10 changed files with 188 additions and 13 deletions

View file

@ -31,18 +31,19 @@ jobs:
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
run: |
set -eu
REF="${GITHUB_SHA:-main}"
REF="${GITHUB_SHA:?exact source revision is required}"
echo "${REF}" | grep -Eq '^[0-9a-f]{40}$'
SHORT="${REF:0:7}"
mkdir -p buildctx "${HOME}/bin"
wget -qO /tmp/repo.tar.gz \
"https://forgejo.coulomb.social/${GITHUB_REPOSITORY}/archive/${SHORT}.tar.gz"
"https://forgejo.coulomb.social/${GITHUB_REPOSITORY}/archive/${REF}.tar.gz"
tar xzf /tmp/repo.tar.gz -C buildctx --strip-components=1
wget -qO- https://download.docker.com/linux/static/stable/x86_64/docker-27.3.1.tgz \
| tar xz --strip-components=1 -C "${HOME}/bin" docker/docker
export PATH="${HOME}/bin:${PATH}"
echo "${REGISTRY_TOKEN}" | docker login "${REGISTRY}" -u "${REGISTRY_USER}" --password-stdin
IMAGE="${REGISTRY}/${IMAGE_NAME}"
docker build -f buildctx/Containerfile -t "${IMAGE}:latest" -t "${IMAGE}:main-${SHORT}" buildctx
docker build --label "org.opencontainers.image.revision=${REF}" -f buildctx/Containerfile -t "${IMAGE}:latest" -t "${IMAGE}:main-${SHORT}" buildctx
docker push "${IMAGE}:latest"
docker push "${IMAGE}:main-${SHORT}"
echo "pushed ${IMAGE}:latest and ${IMAGE}:main-${SHORT}"

View file

@ -1,4 +1,4 @@
FROM python:3.12-slim@sha256:d764629ce0ddd8c71fd371e9901efb324a95789d2315a47db7e4d27e78f1b0e9
FROM python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1
RUN useradd --create-home --uid 10001 user-engine
WORKDIR /app

View file

@ -0,0 +1,31 @@
---
type: conformance-record
derived: true
derived_from: net-kingdom/canon/standards/security-layer-model_v0.8.md
derived_source_sha256: "3d8298560069ef471fba28d2b1245fb2309328f231dad1a667cdf0ce5a5a7c8b"
updated: "2026-10-11"
---
# user-engine accepted v0.8 checker migration
This owner applies GH-WP-0004-T11's post-flip migration to the confirmed
accepted NetKingdom v0.8 cut, immutable accepted-1 artifact SHA256
3d8298560069ef471fba28d2b1245fb2309328f231dad1a667cdf0ce5a5a7c8b.
The checker names that artifact and its local scope in every run. INTENT
frontmatter remains authoritative and the sidecar remains derived; a
contradiction is a finding, never hidden by choosing one form. No declaration
acquires a standard version.
The pin detector follows OpsWarden's A12 r3 reference semantics: standard and
companion identity values (including nested lists), version-bearing paths and
standard/companion version keys are pins; unrelated intent/schema/spec versions
and bare prose provenance are not. Existing local Tooling/contact and capability
detectors remain in place. Historical version strings in negative fixtures are
retained. This source migration grants no native capability or runtime authority.
Validation includes the existing local declaration/contact suite and the same
12-case pin/provenance corpus across all four assigned owners, with exact
accepted-artifact and scope assertions. The local test counts and staged source
digests are retained in the coordinating Custodian evidence receipt. Standalone
checker runs continue to inspect only this repository; no estate-wide compliance
claim or novel declaration is produced.

View file

@ -0,0 +1,31 @@
# Runtime base refresh — 2026-10-11
The exact source-bound application readback candidate failed its independent
scan with 88 HIGH and three CRITICAL OS findings. Preserve that scan and OCI
index bea54ccf in the managed runtime release record. This remediation changes
only the Containerfile's immutable official Python base index from d764629c
to a6e34c59. It preserves Python 3.12, updates patch 3.12.13 to 3.12.15, and
uses current Docker Official Image source commit
2a3b794c223ab067d122719541cdd54a068732a5 (3.12/slim-trixie). The native new
base contains perl-base 5.40.1-6+deb13u1, libc6 deb13u4 and OpenSSL 3.5.7.
Detailed registry/source, exact context, installed file hashes, dependency
snapshot and unfiltered scan are in
`rapp-user-engine/docs/evidence/2026-10-11-readback-base-refresh/`. All 47
copied application inputs and all 45 installed package files match the prior
source. Resolved Python package versions are unchanged. All 20 image readback
tests pass; all 323 source tests pass with 8 optional skips and accepted-v0.8
layer conformance passes. Native consumer acceptance remains USER-WP-0026-T03.
The refreshed scan has zero CRITICAL and 44 HIGH findings across 8 distinct
CVEs, all without a published fixed version in the fresh recorded database.
These findings remain visible; no severity reduction, ignore-unfixed option
or suppression was applied. This does not claim a vulnerability-free or
approved release. Clean accepted source commit, publication and independent
release review remain required, alongside exact scoped live rollout permission.
CI source preparation also replaces short-revision archive lookup with the
validated full 40-hex GITHUB_SHA and labels the built image with that exact
revision. Both workflow shell blocks pass bash syntax checks. This workflow
change is outside the local image runtime context and was not published or
executed; owner CI must produce a new publication receipt from a clean commit.

View file

@ -31,12 +31,11 @@ sys.path.insert(0, str(ROOT / "src"))
from user_engine.layer_yaml import load_mapping, load_mapping_text # noqa: E402
# What every run checks against, printed on every run (GH-DEC-2026-020 §4,
# GH-DEC-2026-021 §2). The accepted text is v0.7 at net-kingdom@66dc491; the
# decision records whose rulings this checker enforces beyond v0.7 are named with it.
# GH-DEC-2026-021 §2). The accepted v0.8 cut incorporates A9-A13 and GH024;
# its immutable publication artifact digest is named in each run.
VALIDATED_AGAINST = (
"net-kingdom/canon/standards/security-layer-model_v0.7.md (net-kingdom@66dc491) "
"as amended by GH-DEC-2026-017, GH-DEC-2026-020 and GH-DEC-2026-021 "
"(A9-A13, A12 r3; gate-house@39d9287)"
"net-kingdom/canon/standards/security-layer-model_v0.8.md "
"(accepted-1 sha256:3d8298560069ef471fba28d2b1245fb2309328f231dad1a667cdf0ce5a5a7c8b)"
)
# What every run ranges over. Stance, claims and classification maps
@ -148,6 +147,9 @@ def load_intent_layer() -> str:
if "layer" not in front:
print(f"FAIL: {INTENT.name} frontmatter has no 'layer:' key (§11)", file=sys.stderr)
raise SystemExit(2)
if fold(front.get("role", "")) != "pip":
print("FAIL: INTENT.md governing role disagrees with derived Engine/PIP declaration", file=sys.stderr)
raise SystemExit(2)
return str(front["layer"])

View file

@ -137,12 +137,12 @@ class ApplicationAccessReader:
self.bound_applications = bound_applications
self.cache_ttl = cache_ttl
self.clock = clock
self._cache: dict[tuple[str, str, str], _CacheEntry] = {}
self._cache: dict[tuple[str, str, str, str], _CacheEntry] = {}
def rows(self, actor: Actor, session_key: str) -> tuple[ApplicationAccessRow, ...] | None:
"""Return rendered rows, or None when the catalogue itself is unreadable."""
now = self.clock()
key = (session_key, actor.issuer, actor.subject)
key = (session_key, actor.issuer, actor.subject, actor.tenant)
entry = self._cache.get(key)
if entry is None or entry.reuse_until <= now:
entry = self._read(actor, now)

View file

@ -3,6 +3,7 @@ import json
import os
import tempfile
import unittest
from dataclasses import replace
from datetime import UTC, datetime, timedelta
from unittest.mock import patch
from urllib.error import HTTPError, URLError
@ -159,6 +160,21 @@ class ReaderTests(unittest.TestCase):
reader.rows(_actor("alice"), "s1")
self.assertEqual(len(readback.reads), 3)
def test_tenant_switch_cannot_reuse_another_tenants_allow(self):
readback = _FakeReadback([
ReadbackResult("informed-decision", "allow", NOW + timedelta(seconds=30), "decision:1"),
])
reader = self._reader(readback)
actor = _actor()
self.assertEqual(reader.rows(actor, "s1")[0].status, "available")
readback.results = [ReadbackResult("informed-decision", "deny")]
other_tenant = replace(actor, tenant="tenant-b")
self.assertEqual(reader.rows(other_tenant, "s1")[0].status, "denied")
self.assertEqual(len(readback.reads), 2)
reader.forget("s1")
reader.rows(actor, "s1")
self.assertEqual(len(readback.reads), 3)
def test_read_failure_is_unchecked_and_not_reused(self):
readback = _FakeReadback([], fail_read=True)
reader = self._reader(readback)

View file

@ -0,0 +1,46 @@
"""Accepted A12 r3 semantics, retaining local contact scanners and scope."""
import importlib.util
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
SCRIPT = ROOT / "scripts/check_layer_conformance.py"
def checker():
spec = importlib.util.spec_from_file_location("v08_checker", SCRIPT)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
@pytest.mark.parametrize("value,pinned", [
({"intent_version": "0.3"}, False),
({"spec_version": "0.7"}, False),
({"note": "per v0.6 section 13"}, False),
({"note": "revised 0.7 wording"}, False),
({"schema_version": "0.1"}, False),
({"standard": "security-layer-model 0.8"}, True),
({"STANDARD": ["security-layer-model v0.8"]}, True),
({"companion": [["SECURITY-COMPANION v0.3"]]}, True),
({"nested": {"standard_version": "0.8"}}, True),
({"nested": {"companion_version": "0.3"}}, True),
({"references": ["security-layer-model@0.8"]}, True),
({"references": ["security-layer-model_v0.7.md"]}, True),
])
def test_reference_pin_provenance_semantics(value, pinned):
module = checker()
assert bool(module.find_versions(value, "test")) is pinned
def test_run_names_exact_accepted_standard_and_scope():
module = checker()
assert "security-layer-model_v0.8.md" in module.VALIDATED_AGAINST
assert "3d8298560069ef471fba28d2b1245fb2309328f231dad1a667cdf0ce5a5a7c8b" in module.VALIDATED_AGAINST
assert "INTENT.md" in module.SCOPE
def test_governing_role_disagreement_is_a_finding(tmp_path, monkeypatch):
module = checker()
intent = tmp_path / "INTENT.md"
intent.write_text("---\nlayer: Engine\nrole: PDP\n---\n")
monkeypatch.setattr(module, "INTENT", intent)
with pytest.raises(SystemExit) as caught:
module.load_intent_layer()
assert caught.value.code == 2

View file

@ -0,0 +1,30 @@
---
id: USER-WP-ADHOC-2026-10-11
type: workplan
title: "Refresh vulnerable readback candidate runtime base"
domain: communication
repo: user-engine
status: finished
flavor: implementation
owner: codex
topic_slug: user-engine
created: "2026-10-11"
updated: "2026-10-11"
---
## Refresh immutable Python patch base and verify exact application preservation
```task
id: USER-WP-ADHOC-2026-10-11-T01
status: done
priority: high
```
Replace only the Containerfile base digest with the current official Python 3.12
index; retain exact application bytes and resolved Python dependency versions.
The bounded local candidate removes all 3 CRITICAL and44 of 88 HIGH OS findings.
Retain remaining 44 unfixed HIGH findings in the unfiltered fresh scan. Exact
source/image/provenance checks and 20 image / 323 source tests pass. Evidence:
`docs/evidence/2026-10-11-runtime-base-refresh.md`. This source remediation
finishes no deployment: USER-WP-0026-T03 and USER-WP-0028-T02 retain native
consumer acceptance, clean source commit/publication and scoped rollout gates.

View file

@ -62,8 +62,8 @@ logout. This does not accept the remaining multi-user Vergabe pilot.
```task
id: USER-WP-0026-T03
status: wait
blocked_on: message-from:access-engine
blocking_reason: "Needs access-engine's per-identity decision/grant/revocation/readback contract and a readable protected-system registry (with key-cape client binding) as the workload catalogue; the membership store cannot represent the allow list."
blocked_on: message-from:rapp-user-engine
blocking_reason: "FLEX-WP-0035-T04 delivered the admitted readback pin on 2026-10-10. Needs rapp-user-engine readback URL, separate projected caller token and exact-pin egress, an image containing the readback client, and native consumer allow/deny/unavailable acceptance against the live pin."
priority: high
state_hub_task_id: "95e9a6d4-7e57-5483-97c5-3f4a45bb6767"
```
@ -147,3 +147,21 @@ despite its `message-from:net-kingdom` qualifier (added 2026-09-28). Sent one
now (message `db1b7d6e`): does NetKingdom own the workload catalogue/admission
record and the scoped access-decision contract, and if not, who does. The
qualifier stays on net-kingdom until it answers or names another owner.
2026-10-10 security consolidation review: FLEX-WP-0035-T04 is done. Its founder-run
Helm upgrades placed lifecycle v2 and application-readback on image e8c57c18;
Ready and anonymous 401/non-enforcement 404 checks passed. Those provider
receipts do not establish user-engine caller acceptance. The canonical apply
home, rapp-user-engine/manifests/runtime.yaml, currently has no readback URL
or dedicated projected-token mount and permits flex-auth egress only to the
enforcement pin. Remaining owner work: wire USER_ENGINE_READBACK_URL and
USER_ENGINE_READBACK_TOKEN_FILE to a separate audience flex-auth projection,
permit only the application-readback pod selector, promote the immutable image
containing this client, and verify native consumer readback without disclosing
a token. Reuse that acceptance for USER-WP-0028-T02; it is the same integration
boundary. No grant, browser acceptance or live deployment is inferred here.
The local readback cache now binds each row set to tenant as well as session,
issuer and subject. A tenant switch within the same session therefore performs
a fresh read instead of displaying another tenant's unexpired allow. A focused
regression exercises an allow in tenant-a followed by a deny in tenant-b.