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.

+
+ Open federated index +
+ +
+ + +--- +# 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.

++
++ Open federated index ++
++ ++
++ ++ ++--- ++# 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-values.proposed.yaml b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-values.proposed.yaml +new file mode 100644 +index 0000000..6e6f81e +--- /dev/null ++++ b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-values.proposed.yaml +@@ -0,0 +1,21 @@ ++# PROPOSAL ONLY; digest is locally built, NOT published. ++# Publish exact reviewed artifact and verify registry digest before any apply. ++image: ++ repository: forgejo.coulomb.social/coulomb/reuse-surface ++ digest: sha256:2364b7e7859daccf9340a063654e2b09eed1bc27e0adf7b23cbb4b30135a7db0 ++authSourceAllowlist: ++ 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 +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-values.proposed.yaml b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-values.proposed.yaml new file mode 100644 index 0000000..6e6f81e --- /dev/null +++ b/docs/assessments/cust81-private-reader/phase-a-local-image-r1/phase-a-values.proposed.yaml @@ -0,0 +1,21 @@ +# PROPOSAL ONLY; digest is locally built, NOT published. +# Publish exact reviewed artifact and verify registry digest before any apply. +image: + repository: forgejo.coulomb.social/coulomb/reuse-surface + digest: sha256:2364b7e7859daccf9340a063654e2b09eed1bc27e0adf7b23cbb4b30135a7db0 +authSourceAllowlist: + 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 diff --git a/docs/assessments/cust81-private-reader/preparation-manifest-r2.json b/docs/assessments/cust81-private-reader/preparation-manifest-r2.json new file mode 100644 index 0000000..e60e14c --- /dev/null +++ b/docs/assessments/cust81-private-reader/preparation-manifest-r2.json @@ -0,0 +1,29 @@ +{ + "proposal_id": "CUST81-APPS-PRIVATE-READER-RELEASE-R1", + "status": "local_verified_live_blocked", + "real_image_digest": null, + "live_execution": false, + "cost_estimate_eur": null, + "risk_estimate_eur": null, + "estimate_status": "live cost/loss bounds require release-specific runtime headroom, recovery and image evidence; not executable before supervisor-approved estimates", + "paths": { + "charts/reuse-surface/templates/_helpers.tpl": "sha256:789606a31ac8da6dfb7a5f6ace6a77269e3be3867d2e9a11e52b19aadf6977df", + "charts/reuse-surface/templates/deployment.yaml": "sha256:2ec0be6d9aa24ed026b0c6629ab8ba003669eb0460d722fe413cd4934111540c", + "charts/reuse-surface/values.schema.json": "sha256:ea73e027e4dcd832cc0bd48fc7ccfa29158153033ca02a8dc7b25b7df0d6c2b5", + "charts/reuse-surface/values.yaml": "sha256:d1aeff71df0c53e4ecb3f4ebaac50ced7691b52c673fe9b49fbaeee6ca02c226", + "docs/assessments/cust81-private-reader/apps-owner-review-r2.md": "sha256:a3a2f2db6f0a8461a0d8299825c842c8ce427f59c86238884609d463837b3b75", + "docs/assessments/cust81-private-reader/local-verification-r2.json": "sha256:d723561845a05a76be9554596011c267fc67dd24953160f3bd7bd26a85c4812c", + "docs/assessments/cust81-private-reader/private-reader-values.r1.yaml": "sha256:e02a319aca9c4860cdb8338009e60af6723bdb1fc17a591db0824273206eff83", + "docs/assessments/cust81-private-reader/reuse-surface-runtime-externalsecret.r1.yaml": "sha256:adfb34c0ee4d01bc602f57cd2320f1658465fb8f8660978828fffa05a5b604b5", + "docs/assessments/cust81-private-reader/runtime-auth-source-allowlist-r1.json": "sha256:e1948c537e206b30fc72b9e4732a3f600d92e131813e6f7ecfd4bfbb18c27286", + "docs/assessments/cust81-private-reader/supervision-preparation-r1.json": "sha256:232f195026d704164b5973b5098002205445ff3ed6b0d2dd0c4a3c92c6ad9ca5", + "docs/assessments/cust81-private-reader/verify_preparation.py": "sha256:c07921ea3fcd7c646aa6f28f34f7cdcb552e893341fe53dc7102ee376541d04d", + "scripts/reuse_authenticated_source_inventory.py": "sha256:42eed5513db090d338daec39258b89a4ce2e9369d175c3c8312904ed68867ee1", + "workplans/RAPPS-WP-0017-reuse-private-reader-release.md": "sha256:3a114a461647b46f3cc8e0ff9aa16b69aed0429cbc1578edf9b0fed5e220cc55" + }, + "chart_patch_sha256": "39ebaa7f4050f9204fe8ee38364fbbce874903447ac45ccd408cf434aa6e4a73", + "revision": 2, + "refinement_or_rescue": true, + "original_revision_preserved": "root owner-assembly/apps-r1 archive", + "correction": "pod SQL native registration url projection plus exact SQLite readonly fixture, safe legacy routes and untrusted successful output refusal" +} diff --git a/docs/assessments/cust81-private-reader/private-reader-values.r1.yaml b/docs/assessments/cust81-private-reader/private-reader-values.r1.yaml new file mode 100644 index 0000000..70dc932 --- /dev/null +++ b/docs/assessments/cust81-private-reader/private-reader-values.r1.yaml @@ -0,0 +1,5 @@ +# PREPARATION ONLY: empty digest deliberately prevents rendering/deployment. +# Fill only after reuse-surface publishes and reviews the fully hardened image. +image: + digest: "" +authSourceAllowlist: {"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"]} diff --git a/docs/assessments/cust81-private-reader/reuse-surface-runtime-externalsecret.r1.yaml b/docs/assessments/cust81-private-reader/reuse-surface-runtime-externalsecret.r1.yaml new file mode 100644 index 0000000..3822799 --- /dev/null +++ b/docs/assessments/cust81-private-reader/reuse-surface-runtime-externalsecret.r1.yaml @@ -0,0 +1,46 @@ +# PROPOSAL ONLY: phase B, after hardened runtime verified and CCR approved. +# reuse-surface hub runtime secrets from OpenBao (RAILIANCE-WP-0011 / CCR-2026-0005). +# +# OpenBao path (platform KV v2): workloads/reuse/reuse-surface/runtime-secrets +# Fields: REUSE_SURFACE_TOKEN, REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET +# +# Prereqs on railiance01: +# - External Secrets Operator (make eso-deploy) +# - ClusterSecretStore openbao-reuse (railiance-platform openbao-secretstore) +# - OpenBao policy workload-kv-read-reuse-surface-runtime + ESO token +# (make reuse-openbao-eso-token-apply) +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: reuse-surface-runtime + namespace: reuse + labels: + app.kubernetes.io/name: reuse-surface + app.kubernetes.io/part-of: railiance-apps +spec: + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: openbao-reuse + target: + # Explicit target metadata prevents ESO copying source last-applied annotations. + template: + metadata: + labels: + app.kubernetes.io/name: reuse-surface + app.kubernetes.io/part-of: railiance-apps + name: reuse-surface-env + creationPolicy: Owner + data: + - secretKey: REUSE_SURFACE_TOKEN + remoteRef: + key: workloads/reuse/reuse-surface/runtime-secrets + property: REUSE_SURFACE_TOKEN + - secretKey: REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET + remoteRef: + key: workloads/reuse/reuse-surface/runtime-secrets + property: REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET + - secretKey: REUSE_SURFACE_FORGEJO_SOURCE_READ_TOKEN + remoteRef: + key: workloads/reuse/reuse-surface/forgejo-source-read + property: FORGEJO_SOURCE_TOKEN diff --git a/docs/assessments/cust81-private-reader/runtime-auth-source-allowlist-r1.json b/docs/assessments/cust81-private-reader/runtime-auth-source-allowlist-r1.json new file mode 100644 index 0000000..edb5f74 --- /dev/null +++ b/docs/assessments/cust81-private-reader/runtime-auth-source-allowlist-r1.json @@ -0,0 +1,18 @@ +{ + "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" + ] +} diff --git a/docs/assessments/cust81-private-reader/source-repair-owner-refinement-r3.json b/docs/assessments/cust81-private-reader/source-repair-owner-refinement-r3.json new file mode 100644 index 0000000..9198919 --- /dev/null +++ b/docs/assessments/cust81-private-reader/source-repair-owner-refinement-r3.json @@ -0,0 +1,24 @@ +{ + "proposal_id": "CUST81-APPS-PRIVATE-READER-RELEASE-R1", + "owner": "railiance-apps", + "review_revision": 3, + "disposition": "approved", + "approved_scope": "ordinary source-only standard digest representation correction; no live runtime change", + "refinement_or_rescue": true, + "original_manifest_sha256": "45d467c2bb48462a388f5df4ba5188492d406bdddbddfbf3487bd2077486dec8", + "qualified_manifest_sha256": "324757f27a36090e34101adf9a68feb8f19530463303e53fec46abe2092943b8", + "source_file_digests_unchanged": true, + "scanner_rule": "generic-api-key", + "affected_field": "paths[docs/assessments/cust81-private-reader/reuse-surface-runtime-externalsecret.r1.yaml]", + "scanner_version": "8.30.1", + "pinned_scanner_sha256": "88f91962aa2f93ac6ab281d553b9e125f5197bbbce38f9f2437f7299c32e5509", + "original_scanner_exit": 20, + "candidate_scanner_exit": 0, + "mechanism": "standard sha256-qualified metadata identifier; unchanged scanner/config, no ignore/exception/bypass", + "backup_ref": "custody/cust81-apps-unpublished-r2", + "original_commits": [ + "4e8e0f5", + "6a8a54d" + ], + "live_execution_approved": false +} diff --git a/docs/assessments/cust81-private-reader/supervision-preparation-r1.json b/docs/assessments/cust81-private-reader/supervision-preparation-r1.json new file mode 100644 index 0000000..722694b --- /dev/null +++ b/docs/assessments/cust81-private-reader/supervision-preparation-r1.json @@ -0,0 +1,10 @@ +{ + "agent": "delegated-railiance-apps-cust81-preparation", + "mode": "supervised", + "scope": "isolated local chart/config/ESO proposal preparation, local verification only", + "supervisor": "root custodian coordinating founder-authorized work", + "promotion_evidence": null, + "runtime_enforcement_verified": false, + "authority_granted": false, + "live_execution_authorized": false +} diff --git a/docs/assessments/cust81-private-reader/verify_preparation.py b/docs/assessments/cust81-private-reader/verify_preparation.py new file mode 100644 index 0000000..df57199 --- /dev/null +++ b/docs/assessments/cust81-private-reader/verify_preparation.py @@ -0,0 +1,94 @@ +"""Local chart and non-disclosure checks only; never contacts a cluster.""" +import hashlib +import importlib.util +import json +from pathlib import Path +import subprocess +import yaml + +ROOT = Path(__file__).resolve().parents[3] +ARTIFACT = Path(__file__).resolve().parent +calls = [] + +def render(extra, success=True): + command = ['helm', 'template', 'reuse', str(ROOT / 'charts/reuse-surface'), '-f', str(ROOT / 'helm/reuse-surface-values.yaml'), *extra] + proc = subprocess.run(command, capture_output=True, text=True) + calls.append({'command': command, 'exit_code': proc.returncode, 'expected_success': success}) + assert (proc.returncode == 0) == success + return list(yaml.safe_load_all(proc.stdout)) if success else [] + +def api(docs): + return next(d for d in docs if d and d.get('kind') == 'Deployment' and d['metadata']['name'] == 'reuse-surface') + +current = api(render([])) +assert current['spec']['template']['spec']['containers'][0]['image'].endswith(':main-6cbc862') +assert next(e['value'] for e in current['spec']['template']['spec']['containers'][0]['env'] if e['name']=='REUSE_SURFACE_AUTH_SOURCE_ALLOWLIST') == '{}' +proposal = ['-f', str(ARTIFACT / 'private-reader-values.r1.yaml')] +render(proposal, False) # unknown real digest is a hard gate +# Synthetic digest is render-only, and expressly not promotion/build evidence. +render(proposal+['--set', 'image.digest=sha256:bad'], False) +render(proposal+['--set-json', 'authSourceAllowlist={"BAD":["http://attacker.invalid"]}', '--set', 'image.digest=sha256:'+'0'*64], False) +docs = render(proposal+['--set', 'image.digest=sha256:'+'0'*64]) +deployment = api(docs) +container = deployment['spec']['template']['spec']['containers'][0] +assert container['image'].endswith('@sha256:'+'0'*64) +allowlist=json.loads(next(e['value'] for e in container['env'] if e['name']=='REUSE_SURFACE_AUTH_SOURCE_ALLOWLIST')) +expected = json.loads((ARTIFACT/'runtime-auth-source-allowlist-r1.json').read_text()) +assert allowlist==expected and len(next(iter(allowlist.values())))==14 +assert deployment['spec']['strategy'] == current['spec']['strategy'] +assert container['resources']==current['spec']['template']['spec']['containers'][0]['resources'] +assert deployment['spec']['template']['spec']['volumes']==current['spec']['template']['spec']['volumes'] +assert container['volumeMounts']==current['spec']['template']['spec']['containers'][0]['volumeMounts'] +secret=yaml.safe_load((ARTIFACT/'reuse-surface-runtime-externalsecret.r1.yaml').read_text()) +baseline=yaml.safe_load((ROOT/'manifests/reuse-surface-runtime-externalsecret.yaml').read_text()) +assert secret['spec']['data'][:-1]==baseline['spec']['data'] +assert secret['spec']['secretStoreRef']==baseline['spec']['secretStoreRef'] +assert secret['spec']['data'][-1]=={'secretKey':'REUSE_SURFACE_FORGEJO_SOURCE_READ_TOKEN','remoteRef':{'key':'workloads/reuse/reuse-surface/forgejo-source-read','property':'FORGEJO_SOURCE_TOKEN'}} +spec=importlib.util.spec_from_file_location('inventory',ROOT/'scripts/reuse_authenticated_source_inventory.py') +mod=importlib.util.module_from_spec(spec);spec.loader.exec_module(mod) +url=expected['REUSE_SURFACE_FORGEJO_SOURCE_READ_TOKEN'][1] +assert len(mod.sanitize([['rapp-openbao','FIXTURE_READ_TOKEN',url]]))==1 +legacy='https://forgejo.coulomb.social/coulomb/rapp-openbao/raw/branch/main/registry/indexes/capabilities.yaml' +assert len(mod.sanitize([['rapp-openbao','FIXTURE_READ_TOKEN',legacy]]))==1 +# Exercise the EXACT pod code against actual native registration keys in SQLite. +# Replacing only the fixture DB path leaves the metadata SELECT/read-only mode intact. +import sqlite3,tempfile +with tempfile.TemporaryDirectory(prefix='apps-reader-fixture-') as temp: + fixture=Path(temp)/'reuse.db' + with sqlite3.connect(fixture) as db: + db.execute('CREATE TABLE registrations(repo TEXT PRIMARY KEY, payload TEXT NOT NULL, registered_at TEXT, updated_at TEXT)') + db.execute('INSERT INTO registrations VALUES(?,?,?,?)', ('rapp-openbao',json.dumps({'repo':'rapp-openbao','url':url,'auth_env':'FIXTURE_READ_TOKEN','description':'fixture-secret-never-emit'}),'fixture','fixture')) + db.execute('INSERT INTO registrations VALUES(?,?,?,?)', ('anonymous',json.dumps({'repo':'anonymous','url':legacy}),'fixture','fixture')) + pod_code=mod.POD_CODE.replace('/data/reuse.db',str(fixture)) + proc=subprocess.run(['python3','-c',pod_code],capture_output=True,text=True,check=True) + assert json.loads(proc.stdout)==[['rapp-openbao','FIXTURE_READ_TOKEN',url]] + assert 'fixture-secret' not in proc.stdout + assert len(mod.sanitize(json.loads(proc.stdout)))==1 + with sqlite3.connect(fixture) as db: assert db.execute('SELECT count(*) FROM registrations').fetchone()==(2,) + assert 'mode=ro' in pod_code and '$.index_url' not in pod_code + assert 'os.environ' not in pod_code and 'getenv' not in pod_code and 'kubectl' not in pod_code + +for bad in ['https://token@forgejo.coulomb.social/x', url+'&token=fixture-secret','http://attacker.invalid',url+'#fixture-secret',legacy+'?token=fixture-secret',legacy+'/../credentials',legacy+'%3Ftoken=fixture-secret']: + try: mod.sanitize([['rapp-openbao','FIXTURE_READ_TOKEN',bad]]) + except ValueError: pass + else: raise AssertionError('unsafe URL accepted') +# Errors from kubectl are discarded before output; no subprocess invoked in test. +original=mod.subprocess.run +class Failure: + returncode=1;stdout=b'fixture-secret';stderr=b'fixture-secret' +mod.subprocess.run=lambda *args,**kwargs: Failure() +import sys,io,contextlib +argv=sys.argv;sys.argv=['inventory','--kubeconfig','fixture-path'] +buf=io.StringIO() +with contextlib.redirect_stdout(buf): assert mod.main()==1 +assert 'fixture-secret' not in buf.getvalue() +class UnsafeSuccess: + returncode=0;stdout=json.dumps([['rapp-openbao','FIXTURE_READ_TOKEN',url+'&token=fixture-secret']]).encode();stderr=b'' +mod.subprocess.run=lambda *args,**kwargs: UnsafeSuccess() +buf=io.StringIO() +with contextlib.redirect_stdout(buf): assert mod.main()==1 +assert 'fixture-secret' not in buf.getvalue() +sys.argv=argv;mod.subprocess.run=original +result={'status':'passed','local_only':True,'real_image_digest':None,'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':calls} +(ARTIFACT/'local-verification-r2.json').write_text(json.dumps(result,indent=2)+'\n') +print(json.dumps({'status':'passed','checks':len(result['checks'])})) diff --git a/scripts/reuse_authenticated_source_inventory.py b/scripts/reuse_authenticated_source_inventory.py new file mode 100644 index 0000000..aea33a5 --- /dev/null +++ b/scripts/reuse_authenticated_source_inventory.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +"""Read-only authenticated source metadata; never read env or Kubernetes Secrets. + +Caller must first confirm the kubeconfig targets railiance01. Raw command +stdout/stderr and exception text are never emitted. No credentials are needed +beyond the caller's separately approved Kubernetes observation/exec lane. +""" +import argparse +import json +import re +import subprocess +from urllib.parse import urlsplit, parse_qs + +# SQL projects metadata only; the registration payload itself is never printed. +POD_CODE = '''import json, sqlite3 +with sqlite3.connect("file:/data/reuse.db?mode=ro", uri=True) as db: + rows=db.execute("SELECT repo, json_extract(payload, '$.auth_env'), json_extract(payload, '$.url') FROM registrations WHERE json_extract(payload, '$.auth_env') IS NOT NULL AND json_extract(payload, '$.auth_env') != ''").fetchall() + print(json.dumps(rows)) +''' + + +def sanitize(rows): + result = [] + for repo, name, url in rows: + if not isinstance(repo, str) or not re.fullmatch(r'[a-zA-Z0-9_.-]{1,128}', repo): + raise ValueError('invalid metadata') + if not isinstance(name, str) or not re.fullmatch(r'[A-Z][A-Z0-9_]{0,127}', name): + raise ValueError('invalid metadata') + parts = urlsplit(url) + # URLs are untrusted stored data; refuse userinfo/fragments and arbitrary + # query fields (which could contain credentials). Never echo invalid rows. + query = parse_qs(parts.query, keep_blank_values=True) + if (parts.scheme != 'https' or parts.username or parts.password or parts.fragment + or parts.hostname != 'forgejo.coulomb.social' or parts.port not in (None, 443) + or not (re.fullmatch(r'/api/v1/repos/coulomb/[a-zA-Z0-9_.-]+/raw/registry/indexes/[a-zA-Z0-9_.-]+', parts.path) + or re.fullmatch(r'/coulomb/[a-zA-Z0-9_.-]+/raw/(?:branch|commit|tag)/[a-zA-Z0-9_.-]+/registry/indexes/[a-zA-Z0-9_.-]+', parts.path)) + or any(k != 'ref' for k in query) + or ('ref' in query and (len(query['ref']) != 1 or not re.fullmatch(r'[a-zA-Z0-9_.-]{1,128}', query['ref'][0])))): + raise ValueError('unsafe metadata') + result.append({'repo': repo, 'auth_env': name, 'index_url': url}) + return sorted(result, key=lambda row: row['repo']) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--kubeconfig', required=True) + args = parser.parse_args() + try: + proc = subprocess.run(['kubectl', '--kubeconfig', args.kubeconfig, '-n', 'reuse', + 'exec', 'deployment/reuse-surface', '-c', 'reuse-surface', '--', 'python3', '-c', POD_CODE], + capture_output=True, timeout=30) + if proc.returncode: + raise RuntimeError('inventory unavailable') + rows = sanitize(json.loads(proc.stdout)) + except Exception: + print(json.dumps({'status': 'refused_or_unavailable', 'raw_output_discarded': True})) + return 1 + print(json.dumps({'status': 'verified', 'authenticated_source_count': len(rows), 'sources': rows}, indent=2)) + return 0 + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/workplans/RAPPS-WP-0017-reuse-private-reader-release.md b/workplans/RAPPS-WP-0017-reuse-private-reader-release.md new file mode 100644 index 0000000..0363d08 --- /dev/null +++ b/workplans/RAPPS-WP-0017-reuse-private-reader-release.md @@ -0,0 +1,57 @@ +--- +id: RAPPS-WP-0017 +type: workplan +title: "Release hardened reuse federation with seven-source metadata reader" +domain: financials +repo: railiance-apps +status: proposed +owner: codex +created: "2026-10-15" +updated: "2026-10-15" +flavor: implementation +depends_on: [RPF-WP-0058, REUSE-WP-0025] +--- + +Provisional id in isolated preparation checkout; root integration must confirm +availability. No hub registration, fix-consistency or push until integration. +Source owners approved metadata disclosure under CUST81 R1; that is not approval +for live credential issuance or workload rollout. Apps owns only S5 release. + +## Prepare bounded release contract + +```task +id: RAPPS-WP-0017-T01 +status: done +priority: high +``` + +Prepare chart allowlist/digest support, exact14 URL override and separate phase-B +ESO manifest, own preparation review and meaningful local validation. +Evidence: docs/assessments/cust81-private-reader/apps-owner-review-r1.md. + +## Verify and promote hardened runtime before reader delivery + +```task +id: RAPPS-WP-0017-T02 +status: wait +priority: high +``` + +Wait for published fully hardened image digest/source/tests plus owner reviews +and change authorization. Obtain metadata-only existing auth-source migration +inventory, live headroom/PVC evidence, exact server dry-run/diff, baseline health +and rollback receipt. Phase A deploy excludes reader ESO mapping. + +## Deliver reviewed reader and prove complete hosted discovery + +```task +id: RAPPS-WP-0017-T03 +status: wait +priority: high +``` + +After verified phase A and approved/executed platform CCR, apply phase-B ESO +mapping and restart hardened runtime through reviewed owner lane. Require +sanitized ESO/key-presence proof and reuse native14 fetch/7 entry hashes before +registration. Final CUST81 owner verifies70/70 hosted; rollback revokes/removes +reader before any vulnerable image restoration.