Reject advisory policy envelopes before lifecycle effects
Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
This commit is contained in:
parent
caab9a90ec
commit
1e0df2f4a3
13 changed files with 2854 additions and 0 deletions
122
docs/evidence/2026-10-10-lifecycle-consumer-pin-repair.md
Normal file
122
docs/evidence/2026-10-10-lifecycle-consumer-pin-repair.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
# Lifecycle consumer pin repair — 2026-10-10
|
||||
|
||||
Initial preparation is retained below. The config-only repair was approved and
|
||||
verified live on 2026-10-11; the dated execution appendix distinguishes it from
|
||||
the separate, unpublished purpose-hardening image. No human disposition is claimed.
|
||||
Root agent observed native State Hub `POST /v1/decisions` returning HTTP 503
|
||||
`invalid_decision`, and read only fixed runtime policy fields: lifecycle package
|
||||
`informed-decision.lifecycle`, version `v1`, digest
|
||||
`sha256:cee6a79f74e81d0d389a2c2e2451a92be3434ea9dfcee4986e8c7e6cfdbb1827`.
|
||||
The provider owner pin is now version `v2`, digest
|
||||
`sha256:da01e045fc108adec6b489e5d51f7e57366793016c5a64776963780a6aae457c`.
|
||||
|
||||
Access Engine `pkg/api/canonical.go` defines and emits only envelope contract
|
||||
`flex-auth.decision-record.v1`. FLEX-WP-0035 adds advisory binding purpose
|
||||
`readback`; enforcement binding purpose stays absent. Lifecycle policy version
|
||||
v2 must not be mistaken for envelope contract version v2. Informed Decision's
|
||||
existing exact package/version/digest check correctly refuses a stale pin.
|
||||
Readiness does not prove that a consumer pin matches a provider release.
|
||||
|
||||
Root's sanitized native provider probe returned HTTP 200, envelope contract
|
||||
`flex-auth.decision-record.v1`, binding purpose absent, matched policy version
|
||||
v2, provenance lifecycle package v2/da01e045, and submitted digest match true.
|
||||
Consumer runtime remained v1/cee6a79. Native pod Ready=1 and image 7f5c6cb.
|
||||
Reported CPU requested headroom: 3460m/4000m (86% allocated); this repair retains
|
||||
5m request and Recreate, and does not add a concurrent pod.
|
||||
|
||||
## Exact proposed action
|
||||
|
||||
Stable proposal: `INFD-WP-0009-T02/config-repin-v1`.
|
||||
Update the lifecycle pin in `deploy/lifecycle/admission.candidate.json` and
|
||||
`deploy/lifecycle/service.candidate.json`. Replace immutable runtime ConfigMap
|
||||
`informed-decision-runtime-c81577741a09` with
|
||||
`informed-decision-runtime-6c221878d051`, and update the Deployment's
|
||||
`configuration` volume reference to the new name. Same namespace and service.
|
||||
The runtime JSON differs only in lifecycle version/digest.
|
||||
|
||||
Service image remains
|
||||
`forgejo.coulomb.social/coulomb/informed-decision@sha256:7f5c6cb29c9f70a026bfe30e72934274ddc69261676cf6d476f81dd32812d173`.
|
||||
The existing image needs no source parser patch to consume this owner policy.
|
||||
Local inspected service source HEAD is `bee5ad9af60ab21bcc88423307ce02cc2ab5631b`;
|
||||
local provider source HEAD is `f5fad7c2851708be41c82891430deffe5f4af0ac`.
|
||||
No schema migration, credentials, review-policy pin, audience or network
|
||||
change. Initial lifecycle repair does not implement expansion INFD-WP-0008.
|
||||
|
||||
## Verification
|
||||
|
||||
Real Access Engine HTTP component with synthetic caller custody, current owner
|
||||
lifecycle fixture and existing PolicyClient: three tests passed (one collaboration
|
||||
flow, two stale-pin regressions). Each stale version or digest produces exact
|
||||
503 `invalid_decision`, writes no memo/lifecycle event, then succeeds with the
|
||||
exact current owner pin. This proves restoring compatible policy pins suffices;
|
||||
no parser relaxation is needed. Staged ConfigMap exactly matches the established
|
||||
renderer output for the repinned admission input; retained customizations in
|
||||
the existing Deployment are preserved.
|
||||
|
||||
Before execution: retain exact live Deployment, old runtime ConfigMap, current
|
||||
image digest and database evidence counts; verify live runtime JSON differs from
|
||||
candidate only as reviewed. Run server-side dry-run and diff through the current
|
||||
owner GitOps release path and retain their results. Check railiance01 headroom:
|
||||
existing request is 5m CPU, unchanged; Recreate stops the single writer first.
|
||||
Expect a brief interruption. No concurrent writer is admitted.
|
||||
|
||||
After execution: verify exact same image and new ConfigMap reference, rollout
|
||||
completion and readyz; prove native State Hub registration/publication with
|
||||
stable write keys and retained provider observations/receipts. Ready alone is
|
||||
insufficient. Human acceptance remains a separate human act.
|
||||
|
||||
## Rollback and risk
|
||||
|
||||
Rollback: restore the old Deployment configuration volume reference and its
|
||||
retained immutable ConfigMap through the same GitOps path. Preserve the existing
|
||||
schema-5 database and any new evidence; do not restore an old database merely
|
||||
to revert policy pins. The old pin intentionally returns to fail-closed 503
|
||||
against the v2 provider; coordinate owner rollback only if the provider itself
|
||||
must be reverted. No provider rollback belongs to this proposal.
|
||||
|
||||
No cloud/resource expansion or paid inference; expected incremental cost EUR 0.
|
||||
Risk: brief service interruption and continued refusal if the runtime provider
|
||||
pin differs; verification stops closure until native receipts exist.
|
||||
|
||||
## Source hashes
|
||||
|
||||
See `2026-10-10-lifecycle-consumer-pin-repair.sources.json` for exact original and
|
||||
proposed release artifact SHA-256 values. Supervisor approval, approved digest,
|
||||
executed digest and verified outcome must be recorded by the root executor;
|
||||
this packet supplies preparation only.
|
||||
|
||||
|
||||
## Separate source hardening (not in config-only live proposal)
|
||||
|
||||
PolicyClient now explicitly refuses advisory or malformed binding purpose; only
|
||||
absence or the exact empty string is the canonical enforcement form. Current
|
||||
service image 7f5c6cb does not contain this patch. Unit coverage includes nine
|
||||
purpose variants; a real provider allow envelope with unchanged binding digest,
|
||||
package pins and TTL is injected with `purpose=readback` and must refuse the
|
||||
write, then the original enforcement response succeeds. These tests cover the
|
||||
missing consumer guard without accepting an unpublished envelope v2 contract.
|
||||
INFD-WP-0009-T04 retains separate image preparation/native release work. T02's
|
||||
same-image config repair remains unchanged.
|
||||
|
||||
Validation after source hardening: 73 policy/purpose, real-provider component
|
||||
and deployment-render tests passed; 21 lifecycle-service checks passed. Review
|
||||
controller component checks (53) require its other owner binary and were skipped;
|
||||
they are not counted as verified. No live hardening rollout is claimed.
|
||||
|
||||
## Config-only execution appendix — 2026-10-11
|
||||
|
||||
Founder approved exact revision `7db8485ffecdebfabd77a9daec085553c74bf0bf`.
|
||||
The existing manual Argo Application synced only the new runtime ConfigMap and
|
||||
Deployment, with prune disabled. Application Succeeded/Healthy; generation24
|
||||
observed24 Ready1 and `/readyz`200 were verified. Lifecycle consumer version
|
||||
v2/da01e045 and unchanged service image7f5c6cb were observed. Native State Hub
|
||||
registration/publication succeeded with stable write keys; review delivery later
|
||||
completed after correcting a separate caller packet-validation error.
|
||||
Custodian retains exact approval, rendered digest, executed JSON patch, outcomes
|
||||
and rollback in `docs/evidence/2026-10-10-security-consolidation/`. Original
|
||||
preparation hashes above remain historical evidence, not rewritten approval.
|
||||
|
||||
Purpose-hardening T04 preparation now has a built, scanned local image and
|
||||
synthetic installed/backup checks in `2026-10-11-purpose-hardening/README.md`.
|
||||
That image is neither published nor deployed; config-only approval does not
|
||||
cover it.
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
[
|
||||
{
|
||||
"repo": "informed-decision",
|
||||
"path": "deploy/lifecycle/admission.candidate.json",
|
||||
"original_sha256": "fc5d6fb8ab833f268427d05f01c9c40db4b7fdd30840a5bdd6660dc6277e3cba",
|
||||
"staged_sha256": "22f830736ee56f6ed9b62f47d243e4e24a1b68263b261e78e2f1cfcb85adbd50"
|
||||
},
|
||||
{
|
||||
"repo": "informed-decision",
|
||||
"path": "deploy/lifecycle/service.candidate.json",
|
||||
"original_sha256": "fcfd29e0ed438b8fc3dd2e719db5a914ec3d947775bf38cae8deeb5d2269e954",
|
||||
"staged_sha256": "7a676532836affd6d75c7f1c41a5f937d8c8c809f63e3264ccce612730d5ba7b"
|
||||
},
|
||||
{
|
||||
"repo": "informed-decision",
|
||||
"path": "tests/test_lifecycle_policy_component.py",
|
||||
"original_sha256": "5fc8e57f499ca0c2882d4fcbfc5a5f6af46315d34b3d03d9a3a6dd95e225487b",
|
||||
"staged_sha256": "7a08fece31ddb5fd80ccdb67c5fc2821e328d8751e33c55714fd398982f71039"
|
||||
},
|
||||
{
|
||||
"repo": "informed-decision",
|
||||
"path": "informed_decision/policy.py",
|
||||
"original_sha256": "a00b93b34caee5f190dea750c53b7bca819b993b8ef2f499ef9525d7b8c11842",
|
||||
"staged_sha256": "9d7c1be4cb6199d14ef0aaead5f85951f45b0ccbd7c800a7fde922a253566b62"
|
||||
},
|
||||
{
|
||||
"repo": "informed-decision",
|
||||
"path": "tests/test_policy_client.py",
|
||||
"original_sha256": "7e3285e7b0381612f40c13a2f2b8f92d6520a4415b44437bc7538cf87f5adbf7",
|
||||
"staged_sha256": "2d743fa7f624f667b714be488197cda0cc82056dee44b5457e28786f09447622"
|
||||
}
|
||||
]
|
||||
5
docs/evidence/2026-10-11-purpose-hardening/Containerfile
Normal file
5
docs/evidence/2026-10-11-purpose-hardening/Containerfile
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
FROM forgejo.coulomb.social/coulomb/informed-decision@sha256:7f5c6cb29c9f70a026bfe30e72934274ddc69261676cf6d476f81dd32812d173
|
||||
LABEL org.opencontainers.image.base.digest="sha256:7f5c6cb29c9f70a026bfe30e72934274ddc69261676cf6d476f81dd32812d173"
|
||||
LABEL social.coulomb.source.policy.sha256="9d7c1be4cb6199d14ef0aaead5f85951f45b0ccbd7c800a7fde922a253566b62"
|
||||
LABEL social.coulomb.source.base.revision="7db8485ffecdebfabd77a9daec085553c74bf0bf"
|
||||
COPY policy.py /opt/venv/lib/python3.12/site-packages/informed_decision/policy.py
|
||||
62
docs/evidence/2026-10-11-purpose-hardening/README.md
Normal file
62
docs/evidence/2026-10-11-purpose-hardening/README.md
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# Advisory-purpose hardening image preparation — 2026-10-11
|
||||
|
||||
INFD-WP-0009-T04 remains in progress. This candidate is locally built and tested;
|
||||
it has no registry publication or deployment receipt. Proposal ID:
|
||||
`INFD-WP-0009-T04/purpose-overlay-v1`. No live action is authorized by this packet.
|
||||
|
||||
Base: `forgejo.coulomb.social/coulomb/informed-decision@sha256:7f5c6cb29c9f70a026bfe30e72934274ddc69261676cf6d476f81dd32812d173`.
|
||||
Base installed policy.py equals HEAD7db8485 policy SHA-256a00b93b34caee5f190dea750c53b7bca819b993b8ef2f499ef9525d7b8c11842.
|
||||
Overlay source SHA-2569d7c1be4cb6199d14ef0aaead5f85951f45b0ccbd7c800a7fde922a253566b62.
|
||||
Only policy.py is added as one layer. Dependency, schema/store, runtime user,
|
||||
entrypoint, env and ports remain exact. `provenance.json` binds source and build
|
||||
recipe; source patch remains uncommitted during preparation and no whole-tree
|
||||
commit provenance is claimed.
|
||||
|
||||
Local candidate `informed-decision:purpose-hardening-20261011` has index digest
|
||||
`sha256:b8b58944786015a5375304241c149d1dab885eb539d6d8945f56b01a3c2bc821`,
|
||||
platform manifest918bbdce7337b716edfeb99b9343037dd141bb870aa3f32d7e4394c410c65b7d,
|
||||
configf187897d7322f10e06d53c153a6fa7e6f7403b47a9b59cf6edd12285ec479310.
|
||||
These local digests are not registry receipts. Verify eventual published digest
|
||||
and installed source before authoring a final admitted Deployment pin.
|
||||
|
||||
Evidence: `checks.json` proves base layer/config equality and fresh scan DB
|
||||
(2026-10-10 updated18:59Z, downloaded23:32Z), zero HIGH/CRITICAL findings.
|
||||
`scan.json` retains package findings; scanner warns Alpine3.24 is not on its
|
||||
EOL list. Vulnerability scan is bounded and not a universal security claim.
|
||||
`container.json` retains 13 checks, including private single writer, uncertain
|
||||
submission preservation, restart, consistent backup and separate synthetic
|
||||
restore. All temporary containers/volumes were removed. `installed-purpose.py`
|
||||
passes 10 installed-client forms: absent and empty allow, eight other/advisory
|
||||
forms refuse. Native identity/PDP/approval/audit proof is not claimed.
|
||||
|
||||
Rebuild: make a fresh private temporary context, copy exact policy.py from owner
|
||||
source and this Containerfile to it, check both hashes against provenance.json,
|
||||
then `docker build --network none --pull=false -f <context>/Containerfile -t
|
||||
informed-decision:purpose-hardening-20261011 <context>`. Use only the immutable
|
||||
base and these files; normal repo .dockerignore excludes a direct module copy.
|
||||
No package download or broader dirty-source wheel enters this overlay.
|
||||
|
||||
## Concrete proposed release
|
||||
|
||||
After registry publication/verification, update only admission.candidate.json
|
||||
image and rendered service.candidate.json Deployment image, preserving current
|
||||
ConfigMap6c221878d051, schema5, review/lifecycle policy pins, requester custody,
|
||||
audience, network, PVC, 5m request, replicas1 and Recreate. Retain exact source
|
||||
revision/digest and server dry-run/diff through manual Argo before approval.
|
||||
Obtain separate supervisor approval of that concrete immutable image revision;
|
||||
the config-only7db8485 approval cannot be reused.
|
||||
|
||||
Before cutover retain metadata-only counts and unique consistent native snapshot
|
||||
in protected custody; verify restore with the candidate on a separate protected
|
||||
volume without printing record content or credentials. Synthetic restore here
|
||||
proves mechanism only. Same-schema rollback retains current DB/evidence and
|
||||
restores image7f5c6cb through owner Argo; no data downgrade or replay is intended.
|
||||
Risk: brief Recreate interruption, no concurrent writer; incremental EUR0 for
|
||||
existing infrastructure, no paid inference. This source correction refuses an
|
||||
advisory envelope before effects while preserving exact current enforcement.
|
||||
|
||||
After approved release verify exact image/config, health, current pins and native
|
||||
register/publication with stable keys; inject a native-provider-derived advisory
|
||||
response in an isolated installed-client probe and prove refusal before writes.
|
||||
Do not contaminate production PDP config or create human approvals to test this
|
||||
guard. Reconcile lifecycle/audit receipts and retain failed/uncertain outcomes.
|
||||
27
docs/evidence/2026-10-11-purpose-hardening/checks.json
Normal file
27
docs/evidence/2026-10-11-purpose-hardening/checks.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"candidate_image_id": "sha256:b8b58944786015a5375304241c149d1dab885eb539d6d8945f56b01a3c2bc821",
|
||||
"repo_digests": [
|
||||
"informed-decision@sha256:b8b58944786015a5375304241c149d1dab885eb539d6d8945f56b01a3c2bc821"
|
||||
],
|
||||
"base_layers_preserved": true,
|
||||
"additional_layers": 1,
|
||||
"runtime_config_preserved": {
|
||||
"User": true,
|
||||
"Entrypoint": true,
|
||||
"Cmd": true,
|
||||
"Env": true,
|
||||
"ExposedPorts": true,
|
||||
"WorkingDir": true
|
||||
},
|
||||
"scanner": "aquasec/trivy@sha256:62b1e65e8869bc4b4c6aa4fa2b21595256c7c2f6018a9d9ad61caf87187c1969",
|
||||
"db": {
|
||||
"Version": 2,
|
||||
"NextUpdate": "2026-10-11T18:59:50.889010572Z",
|
||||
"UpdatedAt": "2026-10-10T18:59:50.889010923Z",
|
||||
"DownloadedAt": "2026-10-10T23:32:32.380033131Z"
|
||||
},
|
||||
"high_critical": [],
|
||||
"scan_scope": "candidate OS/package vulnerabilities; not security attestation; scan warning Alpine3.24 not on EOL list",
|
||||
"published": false,
|
||||
"deployed": false
|
||||
}
|
||||
32
docs/evidence/2026-10-11-purpose-hardening/container.json
Normal file
32
docs/evidence/2026-10-11-purpose-hardening/container.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"status": "passed",
|
||||
"image_id": "sha256:b8b58944786015a5375304241c149d1dab885eb539d6d8945f56b01a3c2bc821",
|
||||
"repo_digests": [
|
||||
"informed-decision@sha256:b8b58944786015a5375304241c149d1dab885eb539d6d8945f56b01a3c2bc821"
|
||||
],
|
||||
"checks_passed": 13,
|
||||
"checks": [
|
||||
"installed container entrypoint serves with projected configuration",
|
||||
"non-root read-only runtime has no external network or published port",
|
||||
"private config/database modes enforced; package installer absent",
|
||||
"configured review refuses anonymous access and reports audit-unready status",
|
||||
"private listener refuses anonymous lifecycle access and exposes no browser routes",
|
||||
"public listener exposes no private workload route",
|
||||
"a second writer cannot acquire the active evidence volume",
|
||||
"synthetic uncertain intent and undelivered evidence remain explicit",
|
||||
"consistent backup created while serving; overwrite refused",
|
||||
"SIGTERM closes the serving writer without forced kill",
|
||||
"restart preserves immutable content and unresolved submission without retry",
|
||||
"separate restored volume preserves exact content and unresolved state",
|
||||
"incomplete owner configuration exits before serving"
|
||||
],
|
||||
"fixture_only": true,
|
||||
"external_network": "none",
|
||||
"content_snapshot_sha256": "6ff72dc6578d8a4c0803ec4330e6144ae18c3182e29ab5506b039cedefb468ea",
|
||||
"native_identity_policy_audit_proven": false,
|
||||
"published": false,
|
||||
"deployed": false,
|
||||
"factory_attempts": 0,
|
||||
"paid_model_calls": 0,
|
||||
"cleanup_complete": true
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import copy,json,time
|
||||
from datetime import datetime,timezone
|
||||
from informed_decision.policy import PolicyClient,CONTRACT,submitted_digest
|
||||
pin='sha256:'+'b'*64
|
||||
req={'id':'image-purpose-fixture','tenant':'tenant:platform','subject':{'id':'synthetic','type':'service','tenant':'tenant:platform'},'resource':{'id':'memo:fixture','type':'memo','system':'informed-decision','tenant':'tenant:platform'},'action':'register','context':{}}
|
||||
class Transport:
|
||||
def request(self,*args,**kwargs):
|
||||
now=time.time(); stamp=lambda t:datetime.fromtimestamp(t,timezone.utc).isoformat()
|
||||
b={**copy.deepcopy({k:req[k] for k in ('tenant','subject','action','resource','context')}),'request_digest':'sha256:'+'e'*64,'submitted_request_digest':submitted_digest(req)}
|
||||
if self.purpose!='ABSENT':b['purpose']=self.purpose
|
||||
d={'id':'synthetic-decision','contract_version':CONTRACT,'request_id':req['id'],'effect':'allow','matched_policy_version':'v1','subject':req['subject'],'resource':req['resource'],'binding':b,'lifetime':{'kind':'ttl','not_before':stamp(now-1),'expires_at':stamp(now+60)},'provenance':{'policy_package':'fixture','policy_version':'v1','policy_package_digest':pin,'registry_snapshot_digest':'sha256:'+'c'*64,'evaluator':'flex-auth/fixture','decision_time':stamp(now)}}
|
||||
return 200,d
|
||||
checks=[]
|
||||
for purpose in ('ABSENT','','readback','enforcement','unknown',None,False,0,[],{}):
|
||||
t=Transport();t.purpose=purpose
|
||||
c=PolicyClient('https://fixture.invalid',lambda:'synthetic-only',package='fixture',version='v1',package_digest=pin,transport=t)
|
||||
o=c.check(req)
|
||||
if purpose in ('ABSENT',''):assert o.outcome=='allow';o.require_current(time.time())
|
||||
else:assert o.outcome=='invalid_decision' and o.decision_json is None
|
||||
checks.append(str(purpose))
|
||||
print(json.dumps({'installed_image_purpose_variants':len(checks),'binding_forms_allowed':2,'advisory_or_malformed_refused':8,'synthetic_only':True,'native_provider':False}))
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"source_base_revision": "7db8485ffecdebfabd77a9daec085553c74bf0bf",
|
||||
"base_image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:7f5c6cb29c9f70a026bfe30e72934274ddc69261676cf6d476f81dd32812d173",
|
||||
"base_policy_sha256": "a00b93b34caee5f190dea750c53b7bca819b993b8ef2f499ef9525d7b8c11842",
|
||||
"policy_sha256": "9d7c1be4cb6199d14ef0aaead5f85951f45b0ccbd7c800a7fde922a253566b62",
|
||||
"containerfile_sha256": "42277e419014a56c0d24399a3aa45b2b0b27a7c22e0d225110007fa71460d345",
|
||||
"scope": "single policy.py overlay; source correction uncommitted; not a claim whole worktree committed",
|
||||
"tag": "informed-decision:purpose-hardening-20261011"
|
||||
}
|
||||
2354
docs/evidence/2026-10-11-purpose-hardening/scan.json
Normal file
2354
docs/evidence/2026-10-11-purpose-hardening/scan.json
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue