diff --git a/charts/reuse-surface/templates/_helpers.tpl b/charts/reuse-surface/templates/_helpers.tpl
index 1c46bdb..cdcae93 100644
--- a/charts/reuse-surface/templates/_helpers.tpl
+++ b/charts/reuse-surface/templates/_helpers.tpl
@@ -32,11 +32,21 @@ app.kubernetes.io/component: landing
{{- end -}}
{{- define "reuse.image" -}}
+{{- if and .Values.authSourceAllowlist (not .Values.image.digest) -}}
+{{- fail "authenticated source allowlist requires reviewed hardened image.digest" -}}
+{{- end -}}
+{{- if .Values.image.digest -}}
+{{- if not (regexMatch "^sha256:[a-f0-9]{64}$" .Values.image.digest) -}}
+{{- fail "image.digest must be sha256 plus 64 lowercase hex characters" -}}
+{{- end -}}
+{{- printf "%s@%s" .Values.image.repository .Values.image.digest -}}
+{{- else -}}
{{- if not .Values.image.tag -}}
{{- fail "image.tag is required - pin it in helm/reuse-surface-values.yaml" -}}
{{- end -}}
{{- printf "%s:%s" .Values.image.repository .Values.image.tag -}}
{{- end -}}
+{{- end -}}
{{- define "reuse.landingImage" -}}
{{- if not .Values.landing.image.tag -}}
diff --git a/charts/reuse-surface/templates/deployment.yaml b/charts/reuse-surface/templates/deployment.yaml
index b1c47e7..06b815d 100644
--- a/charts/reuse-surface/templates/deployment.yaml
+++ b/charts/reuse-surface/templates/deployment.yaml
@@ -36,6 +36,8 @@ spec:
- secretRef:
name: {{ .Values.envSecretName | quote }}
env:
+ - name: REUSE_SURFACE_AUTH_SOURCE_ALLOWLIST
+ value: {{ .Values.authSourceAllowlist | toJson | quote }}
- name: REUSE_SURFACE_LISTEN_HOST
value: "0.0.0.0"
- name: REUSE_SURFACE_LISTEN_PORT
diff --git a/charts/reuse-surface/values.schema.json b/charts/reuse-surface/values.schema.json
new file mode 100644
index 0000000..7367c10
--- /dev/null
+++ b/charts/reuse-surface/values.schema.json
@@ -0,0 +1,30 @@
+{
+ "$schema": "https://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "properties": {
+ "image": {
+ "type": "object",
+ "properties": {
+ "digest": {
+ "type": "string",
+ "pattern": "^(|sha256:[a-f0-9]{64})$"
+ }
+ }
+ },
+ "authSourceAllowlist": {
+ "type": "object",
+ "propertyNames": {
+ "pattern": "^[A-Z][A-Z0-9_]*$"
+ },
+ "additionalProperties": {
+ "type": "array",
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "pattern": "^https://[^\\s]+$"
+ },
+ "minItems": 1
+ }
+ }
+ }
+}
diff --git a/charts/reuse-surface/values.yaml b/charts/reuse-surface/values.yaml
index fb54e76..0e520d2 100644
--- a/charts/reuse-surface/values.yaml
+++ b/charts/reuse-surface/values.yaml
@@ -1,6 +1,7 @@
image:
repository: forgejo.coulomb.social/coulomb/reuse-surface
tag: ""
+ digest: ""
pullPolicy: IfNotPresent
replicaCount: 1
@@ -26,6 +27,10 @@ resources:
envSecretName: reuse-surface-env
+# Non-secret exact URL bindings for authenticated remote metadata fetches.
+# Nonempty bindings require an immutable digest; use only a reviewed hardened image.
+authSourceAllowlist: {}
+
landing:
enabled: false
image:
diff --git a/docs/assessments/cust81-private-reader/apps-owner-review-r2.md b/docs/assessments/cust81-private-reader/apps-owner-review-r2.md
new file mode 100644
index 0000000..a7f7b1b
--- /dev/null
+++ b/docs/assessments/cust81-private-reader/apps-owner-review-r2.md
@@ -0,0 +1,119 @@
+# Railiance apps preparation review — CUST81 private metadata reader R2
+
+Reviewer: delegated railiance-apps preparation worker, supervised local preparation
+assignment. No promotion evidence or existing own-scope supervision record was
+found; the descriptive preparation record grants no runtime authority. This is
+an S5 release-contract review grounded in INTENT principles 1–5 (workloads,
+release contracts, repeatable operations, explicit S3 handoff, verified health).
+It is not a founder decision, independent platform credential review or reuse
+application source review. No live changes, commits, pushes, hub writes, image
+publishes, login or credential retrieval occurred.
+
+Disposition: **approved for integration as local preparation only; live promotion blocked**.
+Canonical review disposition: `approved`. This accepts the bounded S5 proposal
+and its explicit runtime gates, not live execution or another owner’s review.
+
+## Proposed changes and owner boundaries
+
+The chart accepts an optional immutable image digest, adds a non-secret exact
+`REUSE_SURFACE_AUTH_SOURCE_ALLOWLIST` environment binding, and fails rendering
+when a nonempty allowlist lacks an immutable digest. Schema checks enforce
+HTTPS allowlist entries and valid digest syntax. Production values continue
+using their existing `main-6cbc862` tag; production ExternalSecret is unchanged.
+The preparation override contains exactly 14 reviewed pinned metadata URLs and
+an empty digest deliberately preventing deployment. A synthetic all-zero digest
+in local tests is not an image and must never be promoted.
+
+The proposed phase-B ExternalSecret preserves existing two keys, target metadata
+and existing `openbao-reuse` ClusterSecretStore, adding only
+`REUSE_SURFACE_FORGEJO_SOURCE_READ_TOKEN` from
+`workloads/reuse/reuse-surface/forgejo-source-read:FORGEJO_SOURCE_TOKEN`.
+Platform owns the dedicated KV path/policy/store read scope, CCR-2026-0046 and
+credential issuance; apps neither provisions nor consumes an admin credential.
+
+Digest presence cannot prove the hardened application is included. The reuse
+owner must provide published build digest, source revision, tests and review
+binding *both* authenticated redirect rejection and exact environment-name/URL
+credential routing. A reader must not reach the existing vulnerable runtime.
+
+## Ordered promotion gates — not executed
+
+1. Confirm own-scope supervision and founder change approval, reviewed CCR,
+ exact seven-source owner consent packet and scoped Forgejo read-only issuer
+ receipt. Integrate provisional RAPPS-WP-0017 through root owner coordination.
+2. Run metadata inventory helper with an explicitly verified railiance01
+ kubeconfig; compare existing authenticated registrations with newly
+ fail-closed image behavior. The helper reads only SQLite registration
+ metadata, never env/Secrets, captures command errors and refuses unsafe
+ URLs. If it refuses, resolve via the source owner without emitting raw
+ objects. Any existing authenticated source requires separately reviewed
+ exact URL bindings including capability entry URLs before promotion; do not
+ silently orphan sources or broaden the 14-URL map. Missing inventory blocks
+ phase A. Store only safe names, counts and validated metadata URLs.
+3. Read live release image/revision, replica state, PVC storage/access modes and
+ readiness. Confirm node external IP `92.205.62.239`, not retired coulombcore.
+ Record requested CPU/memory headroom and pending pods before rollout. Existing
+ API requests 100m CPU/256Mi, surge1 requires that much additional allocatable
+ capacity; landing unchanged. Confirm the existing PVC supports simultaneous
+ pod scheduling/mount on this single node; stop if RWO/RWOP or mount conflicts
+ prevent it. No rollout strategy/resource/PVC changes are proposed. Do not
+ change other workloads merely to obtain capacity.
+4. Once a real reviewed digest exists, fill the preparation values; render
+ exact chart with production values plus proposal overrides. Server dry-run
+ and client diff must cover every rendered chart object and the phase-B ESO
+ manifest. Preserve stderr in memory and emit sanitized status only; never
+ print live Secrets, Helm secret values, annotations or raw API failures.
+ Existing release owner and any Argo adoption must be verified before choosing
+ owner Helm upgrade versus GitOps sync; neither is executed here.
+5. Phase A: approved release of hardened digest plus approved allowlist, with
+ existing ESO fields only. Owner Helm path must use atomic upgrade, timeout
+ and wait; verify actual running imageID matches digest, API health/probes,
+ public federation baseline63 and credential-routing refusal/redirect tests.
+ Deployment failure blocks phase B. Database/PVC remains unchanged. Collect a
+ separately approved safe backup/recovery receipt before any risky live release.
+6. Phase B: after verified phase A, execute reviewed platform credential action
+ and ESO reader mapping. Verify only ESO condition/status and key-presence
+ booleans via approved suppressing helpers, then restart/sync the hardened
+ workload so envFrom obtains the reader. Never dump Secret or process env.
+7. Reuse owner runs native exact-byte authenticated proof for all14 URLs and
+ seven capability entries using pinned consent hashes. Only then register
+ seven sources through the scoped write route and verify hosted70/70,
+ no duplicates/conflicting IDs and public federation preserves all63.
+
+## Rollback contract
+
+Before execution capture previous approved release revision, digest/tag and
+safe configuration, public discovery baseline and database recovery receipt.
+If phase A fails before credential delivery, atomic restore of previous release
+is safe because no reader has been supplied. After phase B, **never downgrade to
+vulnerable runtime with reader still available**: revoke the dedicated reader
+at Forgejo/OpenBao via credential owner, remove phase-B ESO mapping and materialized
+reader key through reviewed silent maintenance, restart current hardened pods,
+verify absence/revocation, then restore prior approved chart/image only if needed.
+Metadata registrations may remain inaccessible until re-established; record the
+regression explicitly. Do not roll back the PVC or use stale tokens as recovery.
+
+## Local evidence and limitations
+
+`helm lint charts/reuse-surface -f helm/reuse-surface-values.yaml` passed.
+`python3 docs/assessments/cust81-private-reader/verify_preparation.py` passed ten
+checks, including exact14 roundtrip, digest/schema refusal, retention of current
+strategy/resources/PVC, correct isolated ESO mapping, metadata URL sanitization
+and subprocess error suppression. `local-verification-r2.json` contains command
+statuses without raw output. No cluster inventory, resource headroom,
+server dry-run/diff, image publish, live approval or native fetch has been proven.
+
+## Revision history — same proposal, no second trial
+
+R1 root review found the inventory SQL incorrectly selected `$.index_url` rather
+than the native HubStore registration field `$.url`. R1's local checks did not
+exercise the pod SQL and therefore missed this defect. R1 must not be executed;
+it remains preserved in the root assembly archive. R2 selects `$.url` and tests
+the exact read-only pod SQL against a real SQLite registration payload containing
+`repo`, `url`, `auth_env`, timestamps and an unrelated sentinel description, plus
+an anonymous registration. Only expected names/URL emerge; rows remain unchanged.
+R2 also accepts canonical Forgejo raw branch/commit/tag index routes while still
+refusing userinfo, non-HTTPS, credentials in queries and fragments. Untrusted
+successful subprocess output is refused without raw echo, as are failures.
+No live inventory command has run. This corrective refinement is the same
+CUST81-APPS-PRIVATE-READER-RELEASE proposal revision2, not an unchanged success.
diff --git a/docs/assessments/cust81-private-reader/local-verification-r2.json b/docs/assessments/cust81-private-reader/local-verification-r2.json
new file mode 100644
index 0000000..dbd1366
--- /dev/null
+++ b/docs/assessments/cust81-private-reader/local-verification-r2.json
@@ -0,0 +1,96 @@
+{
+ "status": "passed",
+ "local_only": true,
+ "real_image_digest": null,
+ "synthetic_digest_used_only_to_check_rendering": true,
+ "checks": [
+ "production rendering unchanged except empty fail-closed allowlist",
+ "unknown/malformed digest fails",
+ "HTTP allowlist fails schema",
+ "exact14 URLs roundtrip",
+ "strategy resources PVC retained",
+ "dedicated ESO mapping preserves current fields/store",
+ "metadata sanitizer excludes userinfo/query secrets/fragments",
+ "kubectl failure output discarded",
+ "exact pod SQL real payload URL keys readonly fixture and anonymous filtering",
+ "legacy Forgejo branch URL accepted without weakening credential query refusal"
+ ],
+ "helm_calls": [
+ {
+ "command": [
+ "helm",
+ "template",
+ "reuse",
+ "/tmp/cust81-apps-reader-owner/charts/reuse-surface",
+ "-f",
+ "/tmp/cust81-apps-reader-owner/helm/reuse-surface-values.yaml"
+ ],
+ "exit_code": 0,
+ "expected_success": true
+ },
+ {
+ "command": [
+ "helm",
+ "template",
+ "reuse",
+ "/tmp/cust81-apps-reader-owner/charts/reuse-surface",
+ "-f",
+ "/tmp/cust81-apps-reader-owner/helm/reuse-surface-values.yaml",
+ "-f",
+ "/tmp/cust81-apps-reader-owner/docs/assessments/cust81-private-reader/private-reader-values.r1.yaml"
+ ],
+ "exit_code": 1,
+ "expected_success": false
+ },
+ {
+ "command": [
+ "helm",
+ "template",
+ "reuse",
+ "/tmp/cust81-apps-reader-owner/charts/reuse-surface",
+ "-f",
+ "/tmp/cust81-apps-reader-owner/helm/reuse-surface-values.yaml",
+ "-f",
+ "/tmp/cust81-apps-reader-owner/docs/assessments/cust81-private-reader/private-reader-values.r1.yaml",
+ "--set",
+ "image.digest=sha256:bad"
+ ],
+ "exit_code": 1,
+ "expected_success": false
+ },
+ {
+ "command": [
+ "helm",
+ "template",
+ "reuse",
+ "/tmp/cust81-apps-reader-owner/charts/reuse-surface",
+ "-f",
+ "/tmp/cust81-apps-reader-owner/helm/reuse-surface-values.yaml",
+ "-f",
+ "/tmp/cust81-apps-reader-owner/docs/assessments/cust81-private-reader/private-reader-values.r1.yaml",
+ "--set-json",
+ "authSourceAllowlist={\"BAD\":[\"http://attacker.invalid\"]}",
+ "--set",
+ "image.digest=sha256:0000000000000000000000000000000000000000000000000000000000000000"
+ ],
+ "exit_code": 1,
+ "expected_success": false
+ },
+ {
+ "command": [
+ "helm",
+ "template",
+ "reuse",
+ "/tmp/cust81-apps-reader-owner/charts/reuse-surface",
+ "-f",
+ "/tmp/cust81-apps-reader-owner/helm/reuse-surface-values.yaml",
+ "-f",
+ "/tmp/cust81-apps-reader-owner/docs/assessments/cust81-private-reader/private-reader-values.r1.yaml",
+ "--set",
+ "image.digest=sha256:0000000000000000000000000000000000000000000000000000000000000000"
+ ],
+ "exit_code": 0,
+ "expected_success": true
+ }
+ ]
+}
diff --git a/docs/assessments/cust81-private-reader/owner-review-receipt-r2.json b/docs/assessments/cust81-private-reader/owner-review-receipt-r2.json
new file mode 100644
index 0000000..c81c89b
--- /dev/null
+++ b/docs/assessments/cust81-private-reader/owner-review-receipt-r2.json
@@ -0,0 +1,30 @@
+{
+ "reviewer_owner": "railiance-apps",
+ "reviewer_assignment": "delegated-railiance-apps-cust81-preparation",
+ "disposition": "approved",
+ "approved_scope": "isolated S5 chart/ESO preparation integration only",
+ "live_execution_approval": false,
+ "workitem": "RAPPS-WP-0017",
+ "intent_basis": [
+ "Release Contracts over Source Internals",
+ "Repeatable Operations",
+ "Clear Lower-Layer Handoffs",
+ "Evidence Before Confidence"
+ ],
+ "review_artifact_sha256": "a3a2f2db6f0a8461a0d8299825c842c8ce427f59c86238884609d463837b3b75",
+ "reviewed_manifest_sha256": "45d467c2bb48462a388f5df4ba5188492d406bdddbddfbf3487bd2077486dec8",
+ "reviewed_patch_sha256": "39ebaa7f4050f9204fe8ee38364fbbce874903447ac45ccd408cf434aa6e4a73",
+ "gates": [
+ "unknown reviewed hardened image digest",
+ "metadata-only existing authenticated source inventory/migration",
+ "live node headroom/PVC/readiness survey",
+ "server dry-run and client diff",
+ "release-specific EUR estimates and founder live-change approval",
+ "phase A verified before phase B credential delivery",
+ "approved executed platform credential CCR",
+ "native14 URL/7 metadata hash proof then70/70 hosted"
+ ],
+ "proposal_id": "CUST81-APPS-PRIVATE-READER-RELEASE-R1",
+ "revision": 2,
+ "refinement_or_rescue": true
+}
diff --git a/docs/assessments/cust81-private-reader/phase-a-local-image-r1/apps-owner-release-review.md b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/apps-owner-release-review.md
new file mode 100644
index 0000000..0079fe5
--- /dev/null
+++ b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/apps-owner-release-review.md
@@ -0,0 +1,57 @@
+# Apps concrete phase A proposal review
+
+Disposition: `approved` for proposal preparation and local render only.
+This supplement preserves the reviewed core R2 patch unchanged. It supplies
+actual `reuse` Helm release / `reuse` namespace chart rendering with the locally
+built hardened image digest. It does not authorize publication, execute a live
+change or approve platform's CCR. INTENT basis: source-controlled release
+contracts, explicit S3 handoff and evidence before confidence.
+
+The proposed image is
+`forgejo.coulomb.social/coulomb/reuse-surface@sha256:2364b7e7859daccf9340a063654e2b09eed1bc27e0adf7b23cbb4b30135a7db0`.
+The local build receipt confirms no-network/read-only health and native source
+hash smoke. Registry publication is false. Before apply the exact reviewed
+artifact must be published and independently verified by registry manifest
+digest. If publication changes manifest representation/digest, revise and review
+the bound proposal rather than silently replacing the digest.
+
+Current observations are node `92.205.62.239`, CPU requests3560m of4000m (440m
+free), API100m/256Mi, replicas1 with surge1/unavailable0, PVC
+`reuse-surface-data` Bound RWO1Gi, and Helm ownership without Argo tracking.
+The proposed chart retains resources, strategy and PVC. One100m/256Mi surge fits
+observed CPU headroom; recheck memory, pending pods and node headroom immediately
+before rollout. RWO single-node does not prohibit two pods on that same node,
+but driver mount behavior and SQLite concurrent-access readiness remain
+verification gates. Do not change deployment strategy or PVC to bypass a failure.
+
+Exact readonly authenticated-source inventory is0 at its receipt timestamp.
+This clears the observed migration gate, but recheck before apply; no credential
+or Secret/env was read. Existing Kubernetes-auth `openbao-reuse` store is Ready
+with namespace/ServiceAccount/role matching the consumer; its current
+ExternalSecret contains only the two old fields and remains unchanged in phase A.
+
+Local full-chart render and assertions passed: exact proposed image and14 URL
+allowlist; same100m/256Mi requests; same1surge/0unavailable/replicas1; no Secret,
+ExternalSecret or store objects added. Full chart includes existing landing,
+ingress, services and PVC and must receive normal full-chart server dry-run and
+client diff, not a Deployment-only narrow review.
+
+Incremental infrastructure cost is EUR0 because node, replica steady state,
+requests, services and PVC capacity remain unchanged. Build/registry execution
+cost is not independently accounted. Credible operational loss is qualitative
+and not priced in EUR: rollout failure or concurrent SQLite/PVC access may cause
+service interruption or recovery work. No autopilot grant is inferred. Exact
+human review must accept these estimates and remaining readiness gates.
+
+Before founder-authorized deploy, capture current Helm revision and safe rollback
+reference (old running digest
+`sha256:2c1514cb3f5e1297ffeeac912ba36a70f8a2591588a5a4643bc58293e97132de`),
+known recovery receipt and63 public capability baseline. Use actual Helm release
+`reuse`, namespace`reuse`, owner atomic/wait/timeout path after safe dry-run/diff.
+No exact deploy command is executed by this proposal. Phase A retains the current
+runtime Secret fields and supplies no reader. Verify running imageID, readiness,
+public federation and credential refusal/redirect behavior before phase B.
+If phase A fails with no reader delivered, restore the approved previous release.
+After phase B, revoke/remove reader and verify its absence before any vulnerable
+image restoration. Phase B is independently gated by approved/executed CCR and
+native14 URL/7 entry-hash proof before70/70 hosted discovery.
diff --git a/docs/assessments/cust81-private-reader/phase-a-local-image-r1/manifest.json b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/manifest.json
new file mode 100644
index 0000000..15cc477
--- /dev/null
+++ b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/manifest.json
@@ -0,0 +1,12 @@
+{
+ "proposal_id": "CUST81-APPS-PHASE-A-LOCAL-IMAGE-R1",
+ "reviewer_owner": "railiance-apps",
+ "disposition": "approved",
+ "approved_scope": "preparation only, local full-chart render, supervised founder review required",
+ "files": {
+ "docs/assessments/cust81-private-reader/phase-a-local-image-r1/apps-owner-release-review.md": "a74e96986798a727fc87c0d3c578601579778dfd8521796d0bb81df8451c751b",
+ "docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-full-chart.proposed.yaml": "36c20c3e16757d3e888a3db02853032b33e791aa04a6055fe001121254345b81",
+ "docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-preparation-receipt.json": "3282a17ae3724619e40dd1f34846d83b2297d9ae00030618dbd269e8e2fd7d39",
+ "docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-values.proposed.yaml": "35284857ec987fc7a929f5c2eecdb44c7d3367f7835904692947de09918ab8f1"
+ }
+}
diff --git a/docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-full-chart.proposed.yaml b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-full-chart.proposed.yaml
new file mode 100644
index 0000000..4059c3a
--- /dev/null
+++ b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-full-chart.proposed.yaml
@@ -0,0 +1,478 @@
+# PREPARATION RENDER ONLY; no registry publication or server validation proved.
+---
+# Source: reuse-surface/templates/landing-configmap.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: reuse-surface-landing
+ labels:
+ app.kubernetes.io/name: reuse-surface
+ app.kubernetes.io/instance: reuse
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/version: "0.1.0"
+ app.kubernetes.io/part-of: railiance-apps
+ helm.sh/chart: reuse-surface-0.1.0
+ app.kubernetes.io/component: landing
+data:
+ index.html: |
+
+
+
+
+
+
+
+ REUSE federation endpoint
+
+
+
+
+
reuse.coulomb.social
+
REUSE federation endpoint
+
This is the Railiance REUSE capability federation service. It is an API endpoint for automated clients and operators; there is no browser login for this service.
+
+
+
+
+---
+# Source: reuse-surface/templates/pvc.yaml
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: reuse-surface-data
+ labels:
+ app.kubernetes.io/name: reuse-surface
+ app.kubernetes.io/instance: reuse
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/version: "0.1.0"
+ app.kubernetes.io/part-of: railiance-apps
+ helm.sh/chart: reuse-surface-0.1.0
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+---
+# Source: reuse-surface/templates/landing-service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+ name: reuse-surface-landing
+ labels:
+ app.kubernetes.io/name: reuse-surface
+ app.kubernetes.io/instance: reuse
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/version: "0.1.0"
+ app.kubernetes.io/part-of: railiance-apps
+ helm.sh/chart: reuse-surface-0.1.0
+ app.kubernetes.io/component: landing
+spec:
+ type: ClusterIP
+ selector:
+ app.kubernetes.io/name: reuse-surface
+ app.kubernetes.io/instance: reuse
+ app.kubernetes.io/component: landing
+ ports:
+ - name: http
+ port: 8080
+ targetPort: http
+ protocol: TCP
+---
+# Source: reuse-surface/templates/service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+ name: reuse-surface
+ labels:
+ app.kubernetes.io/name: reuse-surface
+ app.kubernetes.io/instance: reuse
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/version: "0.1.0"
+ app.kubernetes.io/part-of: railiance-apps
+ helm.sh/chart: reuse-surface-0.1.0
+spec:
+ type: ClusterIP
+ selector:
+ app.kubernetes.io/name: reuse-surface
+ app.kubernetes.io/instance: reuse
+ app.kubernetes.io/component: api
+ ports:
+ - name: http
+ port: 8000
+ targetPort: http
+ protocol: TCP
+---
+# Source: reuse-surface/templates/deployment.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: reuse-surface
+ labels:
+ app.kubernetes.io/name: reuse-surface
+ app.kubernetes.io/instance: reuse
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/version: "0.1.0"
+ app.kubernetes.io/part-of: railiance-apps
+ helm.sh/chart: reuse-surface-0.1.0
+ app.kubernetes.io/component: api
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app.kubernetes.io/name: reuse-surface
+ app.kubernetes.io/instance: reuse
+ strategy:
+ type: RollingUpdate
+ rollingUpdate:
+ maxSurge: 1
+ maxUnavailable: 0
+ template:
+ metadata:
+ labels:
+ app.kubernetes.io/name: reuse-surface
+ app.kubernetes.io/instance: reuse
+ app.kubernetes.io/component: api
+ spec:
+ enableServiceLinks: false
+ securityContext:
+ {}
+ containers:
+ - name: reuse-surface
+ image: "forgejo.coulomb.social/coulomb/reuse-surface@sha256:2364b7e7859daccf9340a063654e2b09eed1bc27e0adf7b23cbb4b30135a7db0"
+ imagePullPolicy: IfNotPresent
+ command: ["reuse-surface", "serve"]
+ securityContext:
+ {}
+ ports:
+ - name: http
+ containerPort: 8000
+ protocol: TCP
+ envFrom:
+ - secretRef:
+ name: "reuse-surface-env"
+ env:
+ - name: REUSE_SURFACE_AUTH_SOURCE_ALLOWLIST
+ value: "{\"REUSE_SURFACE_FORGEJO_SOURCE_READ_TOKEN\":[\"https://forgejo.coulomb.social/api/v1/repos/coulomb/rapp-openbao/raw/registry/capabilities/capability.railiance.openbao-package.md?ref=35672be138036c8433a5ac5de91e068c03c2b124\",\"https://forgejo.coulomb.social/api/v1/repos/coulomb/rapp-openbao/raw/registry/indexes/capabilities.yaml?ref=35672be138036c8433a5ac5de91e068c03c2b124\",\"https://forgejo.coulomb.social/api/v1/repos/coulomb/rapp-policy-nexus/raw/registry/capabilities/capability.railiance.policy-publication-package.md?ref=088b78ac03b0cebeec34a69aae3569eb7ec2f9c3\",\"https://forgejo.coulomb.social/api/v1/repos/coulomb/rapp-policy-nexus/raw/registry/indexes/capabilities.yaml?ref=088b78ac03b0cebeec34a69aae3569eb7ec2f9c3\",\"https://forgejo.coulomb.social/api/v1/repos/coulomb/rapp-postgres/raw/registry/capabilities/capability.railiance.postgres-isolation-recovery.md?ref=a9f569c96d74aa384ac8d3ac4aa960e4061550b5\",\"https://forgejo.coulomb.social/api/v1/repos/coulomb/rapp-postgres/raw/registry/indexes/capabilities.yaml?ref=a9f569c96d74aa384ac8d3ac4aa960e4061550b5\",\"https://forgejo.coulomb.social/api/v1/repos/coulomb/rapp-sbom-nexus/raw/registry/capabilities/capability.railiance.sbom-runtime-package.md?ref=adbedd349e8df97be43a1f57db7095af45ff29d1\",\"https://forgejo.coulomb.social/api/v1/repos/coulomb/rapp-sbom-nexus/raw/registry/indexes/capabilities.yaml?ref=adbedd349e8df97be43a1f57db7095af45ff29d1\",\"https://forgejo.coulomb.social/api/v1/repos/coulomb/rapp-telemetry/raw/registry/capabilities/capability.railiance.telemetry-package.md?ref=f158307e24b86bab88a1af4830ff6b4f85afdeb5\",\"https://forgejo.coulomb.social/api/v1/repos/coulomb/rapp-telemetry/raw/registry/indexes/capabilities.yaml?ref=f158307e24b86bab88a1af4830ff6b4f85afdeb5\",\"https://forgejo.coulomb.social/api/v1/repos/coulomb/rapp-tenant-engine/raw/registry/capabilities/capability.railiance.tenant-engine-package.md?ref=9bdc86572728783a5ed94266f04f7b12d414c557\",\"https://forgejo.coulomb.social/api/v1/repos/coulomb/rapp-tenant-engine/raw/registry/indexes/capabilities.yaml?ref=9bdc86572728783a5ed94266f04f7b12d414c557\",\"https://forgejo.coulomb.social/api/v1/repos/coulomb/rapp-user-engine/raw/registry/capabilities/capability.railiance.user-engine-package.md?ref=f35108f9e1b8702fb6c526fe42b2fec5ca032738\",\"https://forgejo.coulomb.social/api/v1/repos/coulomb/rapp-user-engine/raw/registry/indexes/capabilities.yaml?ref=f35108f9e1b8702fb6c526fe42b2fec5ca032738\"]}"
+ - name: REUSE_SURFACE_LISTEN_HOST
+ value: "0.0.0.0"
+ - name: REUSE_SURFACE_LISTEN_PORT
+ value: "8000"
+ - name: REUSE_SURFACE_DB
+ value: "/data/reuse.db"
+ - name: REUSE_SURFACE_CACHE_DIR
+ value: "/data/cache"
+ volumeMounts:
+ - name: data
+ mountPath: /data
+ readinessProbe:
+ httpGet:
+ path: /health
+ port: 8000
+ initialDelaySeconds: 10
+ periodSeconds: 10
+ timeoutSeconds: 5
+ failureThreshold: 3
+ livenessProbe:
+ httpGet:
+ path: /health
+ port: 8000
+ initialDelaySeconds: 15
+ periodSeconds: 30
+ timeoutSeconds: 5
+ failureThreshold: 3
+ resources:
+ limits:
+ cpu: 500m
+ memory: 512Mi
+ requests:
+ cpu: 100m
+ memory: 256Mi
+ volumes:
+ - name: data
+ persistentVolumeClaim:
+ claimName: reuse-surface-data
+---
+# Source: reuse-surface/templates/landing-deployment.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: reuse-surface-landing
+ labels:
+ app.kubernetes.io/name: reuse-surface
+ app.kubernetes.io/instance: reuse
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/version: "0.1.0"
+ app.kubernetes.io/part-of: railiance-apps
+ helm.sh/chart: reuse-surface-0.1.0
+ app.kubernetes.io/component: landing
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app.kubernetes.io/name: reuse-surface
+ app.kubernetes.io/instance: reuse
+ app.kubernetes.io/component: landing
+ strategy:
+ type: RollingUpdate
+ rollingUpdate:
+ maxSurge: 1
+ maxUnavailable: 0
+ template:
+ metadata:
+ labels:
+ app.kubernetes.io/name: reuse-surface
+ app.kubernetes.io/instance: reuse
+ app.kubernetes.io/component: landing
+ spec:
+ enableServiceLinks: false
+ containers:
+ - name: landing
+ image: "nginxinc/nginx-unprivileged:1.27-alpine"
+ imagePullPolicy: IfNotPresent
+ ports:
+ - name: http
+ containerPort: 8080
+ protocol: TCP
+ readinessProbe:
+ httpGet:
+ path: /
+ port: http
+ initialDelaySeconds: 3
+ periodSeconds: 10
+ timeoutSeconds: 3
+ failureThreshold: 3
+ livenessProbe:
+ httpGet:
+ path: /
+ port: http
+ initialDelaySeconds: 10
+ periodSeconds: 30
+ timeoutSeconds: 3
+ failureThreshold: 3
+ resources:
+ limits:
+ cpu: 50m
+ memory: 64Mi
+ requests:
+ cpu: 10m
+ memory: 32Mi
+ volumeMounts:
+ - name: landing-page
+ mountPath: /usr/share/nginx/html/index.html
+ subPath: index.html
+ readOnly: true
+ volumes:
+ - name: landing-page
+ configMap:
+ name: reuse-surface-landing
+---
+# Source: reuse-surface/templates/ingress.yaml
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: reuse-surface
+ labels:
+ app.kubernetes.io/name: reuse-surface
+ app.kubernetes.io/instance: reuse
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/version: "0.1.0"
+ app.kubernetes.io/part-of: railiance-apps
+ helm.sh/chart: reuse-surface-0.1.0
+ annotations:
+ cert-manager.io/cluster-issuer: letsencrypt-prod
+ traefik.ingress.kubernetes.io/router.entrypoints: websecure
+ traefik.ingress.kubernetes.io/router.tls: "true"
+spec:
+ ingressClassName: traefik
+ tls:
+ - hosts:
+ - reuse.coulomb.social
+ secretName: reuse-surface-tls
+ rules:
+ - host: reuse.coulomb.social
+ http:
+ paths:
+ - path: /health
+ pathType: Exact
+ backend:
+ service:
+ name: reuse-surface
+ port:
+ number: 8000
+ - path: /v1
+ pathType: Prefix
+ backend:
+ service:
+ name: reuse-surface
+ port:
+ number: 8000
+---
+# Source: reuse-surface/templates/landing-ingress.yaml
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: reuse-surface-landing
+ labels:
+ app.kubernetes.io/name: reuse-surface
+ app.kubernetes.io/instance: reuse
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/version: "0.1.0"
+ app.kubernetes.io/part-of: railiance-apps
+ helm.sh/chart: reuse-surface-0.1.0
+ annotations:
+ traefik.ingress.kubernetes.io/router.entrypoints: websecure
+ traefik.ingress.kubernetes.io/router.tls: "true"
+ traefik.ingress.kubernetes.io/router.priority: "1"
+spec:
+ ingressClassName: traefik
+ tls:
+ - hosts:
+ - reuse.coulomb.social
+ secretName: reuse-surface-tls
+ rules:
+ - host: reuse.coulomb.social
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: reuse-surface-landing
+ port:
+ number: 8080
+---
+# Source: reuse-surface/templates/redirect-ingress.yaml
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: reuse-surface-http-redirect
+ labels:
+ app.kubernetes.io/name: reuse-surface
+ app.kubernetes.io/instance: reuse
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/version: "0.1.0"
+ app.kubernetes.io/part-of: railiance-apps
+ helm.sh/chart: reuse-surface-0.1.0
+ annotations:
+ traefik.ingress.kubernetes.io/router.entrypoints: web
+ traefik.ingress.kubernetes.io/router.middlewares: "reuse-reuse-surface-redirect-https@kubernetescrd"
+spec:
+ ingressClassName: traefik
+ rules:
+ - host: reuse.coulomb.social
+ http:
+ paths:
+ - path: /
+ pathType: Prefix
+ backend:
+ service:
+ name: reuse-surface
+ port:
+ number: 8000
+---
+# Source: reuse-surface/templates/redirect-middleware.yaml
+apiVersion: traefik.io/v1alpha1
+kind: Middleware
+metadata:
+ name: reuse-surface-redirect-https
+ labels:
+ app.kubernetes.io/name: reuse-surface
+ app.kubernetes.io/instance: reuse
+ app.kubernetes.io/managed-by: Helm
+ app.kubernetes.io/version: "0.1.0"
+ app.kubernetes.io/part-of: railiance-apps
+ helm.sh/chart: reuse-surface-0.1.0
+spec:
+ redirectScheme:
+ scheme: https
+ permanent: true
diff --git a/docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-preparation-receipt.json b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-preparation-receipt.json
new file mode 100644
index 0000000..c58f4b4
--- /dev/null
+++ b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-preparation-receipt.json
@@ -0,0 +1,67 @@
+{
+ "proposal_id": "CUST81-APPS-PHASE-A-LOCAL-IMAGE-R1",
+ "disposition": "approved",
+ "approved_scope": "concrete proposal preparation and local render only; not publish or production deploy",
+ "workitem": "RAPPS-WP-0017-T02",
+ "release": "reuse",
+ "namespace": "reuse",
+ "deployment": "reuse-surface",
+ "image_reference": "forgejo.coulomb.social/coulomb/reuse-surface@sha256:2364b7e7859daccf9340a063654e2b09eed1bc27e0adf7b23cbb4b30135a7db0",
+ "registry_publication_verified": false,
+ "phase_b_credential_delivery_included": false,
+ "incremental_infrastructure_cost_eur": 0,
+ "cost_basis": "existing node, same requests and replicas, same PVC, no new service or purchased capacity; build/registry execution cost not independently accounted",
+ "credible_loss_bound_eur": null,
+ "risk_basis": "qualitative supervised change: transient rollout or SQLite concurrent-access outage; RWO PVC single-node mounts need preflight; no customer production admitted; data recovery and exact atomic rollback required before execution",
+ "autopilot_authority": false,
+ "local_render_checks": "passed",
+ "evidence": {
+ "hardened-reader-local-image-r1.json": {
+ "path": "/home/worsch/the-custodian/docs/assessments/netkingdom-2026-10-14/hardened-reader-local-image-r1.json",
+ "sha256": "ed7c2516925d7f16b573a70b5e48d5656a4875e9eb94bcc8760a8bdcbe07f59c"
+ },
+ "live-authenticated-source-inventory-r1.json": {
+ "path": "/home/worsch/the-custodian/docs/assessments/netkingdom-2026-10-14/live-authenticated-source-inventory-r1.json",
+ "sha256": "ba669d6231c8c611191c7ad28f5914d6c47332032b23b0ea40a13f753e883073"
+ },
+ "reuse-release-runtime-metadata-r1.json": {
+ "path": "/home/worsch/the-custodian/docs/assessments/netkingdom-2026-10-14/reuse-release-runtime-metadata-r1.json",
+ "sha256": "5ec901cf41b9f52628ff636c23b5bbc4789df6a9118f5cff0ff8518b287357e9"
+ },
+ "reuse-release-owner-eso-metadata-r1.json": {
+ "path": "/home/worsch/the-custodian/docs/assessments/netkingdom-2026-10-14/reuse-release-owner-eso-metadata-r1.json",
+ "sha256": "ff9aa207ae081d27d86820747a993d4bbc290ba2c354eef72388233d6733adb3"
+ }
+ },
+ "observed_runtime": {
+ "node_ip": "92.205.62.239",
+ "cpu_free_m": 440,
+ "api_surge_cpu_m": 100,
+ "api_surge_memory_mi": 256,
+ "pvc": "reuse-surface-data",
+ "pvc_access": "ReadWriteOnce",
+ "pvc_capacity": "1Gi",
+ "previous_image_digest": "forgejo.coulomb.social/coulomb/reuse-surface@sha256:2c1514cb3f5e1297ffeeac912ba36a70f8a2591588a5a4643bc58293e97132de",
+ "authenticated_sources": 0
+ },
+ "gates": [
+ "publish exact reviewed image and verify registry digest; local digest may require reviewed update if registry transforms manifest",
+ "founder approval for exact phase A and later credential CCR/phase B",
+ "recheck target headroom memory node/PVC mount scheduling and authenticated inventory immediately before apply",
+ "bounded safe server dry-run/client diff and current release revision/rollback capture",
+ "no ESO reader field during phase A; verify actual imageID health and63public baseline before phase B",
+ "revoke/remove delivered reader before any downgrade to old vulnerable image"
+ ],
+ "render_command": [
+ "helm",
+ "template",
+ "reuse",
+ "charts/reuse-surface",
+ "--namespace",
+ "reuse",
+ "-f",
+ "helm/reuse-surface-values.yaml",
+ "-f",
+ "docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-values.proposed.yaml"
+ ]
+}
diff --git a/docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-supplement.patch b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-supplement.patch
new file mode 100644
index 0000000..bdedf68
--- /dev/null
+++ b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-supplement.patch
@@ -0,0 +1,665 @@
+diff --git a/docs/assessments/cust81-private-reader/phase-a-local-image-r1/apps-owner-release-review.md b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/apps-owner-release-review.md
+new file mode 100644
+index 0000000..0079fe5
+--- /dev/null
++++ b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/apps-owner-release-review.md
+@@ -0,0 +1,57 @@
++# Apps concrete phase A proposal review
++
++Disposition: `approved` for proposal preparation and local render only.
++This supplement preserves the reviewed core R2 patch unchanged. It supplies
++actual `reuse` Helm release / `reuse` namespace chart rendering with the locally
++built hardened image digest. It does not authorize publication, execute a live
++change or approve platform's CCR. INTENT basis: source-controlled release
++contracts, explicit S3 handoff and evidence before confidence.
++
++The proposed image is
++`forgejo.coulomb.social/coulomb/reuse-surface@sha256:2364b7e7859daccf9340a063654e2b09eed1bc27e0adf7b23cbb4b30135a7db0`.
++The local build receipt confirms no-network/read-only health and native source
++hash smoke. Registry publication is false. Before apply the exact reviewed
++artifact must be published and independently verified by registry manifest
++digest. If publication changes manifest representation/digest, revise and review
++the bound proposal rather than silently replacing the digest.
++
++Current observations are node `92.205.62.239`, CPU requests3560m of4000m (440m
++free), API100m/256Mi, replicas1 with surge1/unavailable0, PVC
++`reuse-surface-data` Bound RWO1Gi, and Helm ownership without Argo tracking.
++The proposed chart retains resources, strategy and PVC. One100m/256Mi surge fits
++observed CPU headroom; recheck memory, pending pods and node headroom immediately
++before rollout. RWO single-node does not prohibit two pods on that same node,
++but driver mount behavior and SQLite concurrent-access readiness remain
++verification gates. Do not change deployment strategy or PVC to bypass a failure.
++
++Exact readonly authenticated-source inventory is0 at its receipt timestamp.
++This clears the observed migration gate, but recheck before apply; no credential
++or Secret/env was read. Existing Kubernetes-auth `openbao-reuse` store is Ready
++with namespace/ServiceAccount/role matching the consumer; its current
++ExternalSecret contains only the two old fields and remains unchanged in phase A.
++
++Local full-chart render and assertions passed: exact proposed image and14 URL
++allowlist; same100m/256Mi requests; same1surge/0unavailable/replicas1; no Secret,
++ExternalSecret or store objects added. Full chart includes existing landing,
++ingress, services and PVC and must receive normal full-chart server dry-run and
++client diff, not a Deployment-only narrow review.
++
++Incremental infrastructure cost is EUR0 because node, replica steady state,
++requests, services and PVC capacity remain unchanged. Build/registry execution
++cost is not independently accounted. Credible operational loss is qualitative
++and not priced in EUR: rollout failure or concurrent SQLite/PVC access may cause
++service interruption or recovery work. No autopilot grant is inferred. Exact
++human review must accept these estimates and remaining readiness gates.
++
++Before founder-authorized deploy, capture current Helm revision and safe rollback
++reference (old running digest
++`sha256:2c1514cb3f5e1297ffeeac912ba36a70f8a2591588a5a4643bc58293e97132de`),
++known recovery receipt and63 public capability baseline. Use actual Helm release
++`reuse`, namespace`reuse`, owner atomic/wait/timeout path after safe dry-run/diff.
++No exact deploy command is executed by this proposal. Phase A retains the current
++runtime Secret fields and supplies no reader. Verify running imageID, readiness,
++public federation and credential refusal/redirect behavior before phase B.
++If phase A fails with no reader delivered, restore the approved previous release.
++After phase B, revoke/remove reader and verify its absence before any vulnerable
++image restoration. Phase B is independently gated by approved/executed CCR and
++native14 URL/7 entry-hash proof before70/70 hosted discovery.
+diff --git a/docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-full-chart.proposed.yaml b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-full-chart.proposed.yaml
+new file mode 100644
+index 0000000..4059c3a
+--- /dev/null
++++ b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-full-chart.proposed.yaml
+@@ -0,0 +1,478 @@
++# PREPARATION RENDER ONLY; no registry publication or server validation proved.
++---
++# Source: reuse-surface/templates/landing-configmap.yaml
++apiVersion: v1
++kind: ConfigMap
++metadata:
++ name: reuse-surface-landing
++ labels:
++ app.kubernetes.io/name: reuse-surface
++ app.kubernetes.io/instance: reuse
++ app.kubernetes.io/managed-by: Helm
++ app.kubernetes.io/version: "0.1.0"
++ app.kubernetes.io/part-of: railiance-apps
++ helm.sh/chart: reuse-surface-0.1.0
++ app.kubernetes.io/component: landing
++data:
++ index.html: |
++
++
++
++
++
++
++
++ REUSE federation endpoint
++
++
++
++
++
reuse.coulomb.social
++
REUSE federation endpoint
++
This is the Railiance REUSE capability federation service. It is an API endpoint for automated clients and operators; there is no browser login for this service.