Establish Coulomb scoped recovery API custody and native boundaries
Some checks are pending
CCR intake gate / gate (push) Waiting to run
CI Smoke / container-smoke (push) Waiting to run
CI Smoke / host-smoke (push) Waiting to run

Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a17f16-d99c-7ea3-95f0-8212897fba6b
This commit is contained in:
codex 2026-10-29 22:13:06 +01:00
parent ccc0f8b578
commit 849f3947dc
8 changed files with 784 additions and 13 deletions

View file

@ -0,0 +1,45 @@
{
"schema": "platform.coulomb-recovery-api.v1",
"project_id": "06d107bc-9d84-4672-b2a0-95701cc0c07f",
"region": "nl-ams",
"custody_owner": "railiance-platform/platform-root",
"public_recipient": "age1qm30jk8q0cezey652dk2dhcr3d9vs528v6lg8mavl6d4q3e3vgnqmrmyy3",
"materials": {
"age": {
"id": "634e4b9f-0b61-4329-a83c-1ed0e76c4636",
"revision": 1,
"name": "coulomb-social-age-recovery"
},
"reader-pair": {
"id": "241742f7-d3b5-4163-8d87-3a3d9585778d",
"revision": 1,
"name": "coulomb-social-recovery-reader-api"
},
"custodian-pair": {
"id": "cf44e9bd-9edc-450b-9f10-564ee3008305",
"revision": 1,
"name": "coulomb-social-recovery-custodian-api"
}
},
"applications": {
"custodian": "f80037a2-87c9-44d2-9163-3e6907af3ced",
"reader": "7a4055fc-a3f5-40bf-8013-cd0eec9028de"
},
"routine_key_expirations": {
"reader": "2027-10-28T19:24:59.647270Z",
"custodian": "2027-10-28T19:25:00.458446Z"
},
"buckets": {
"kits": {
"name": "railiance-coulomb-social-recovery",
"prefix": "kits/",
"automatic_expiry_enabled": false
},
"archives": {
"name": "railiance-coulomb-social-archives",
"prefix": "archives/",
"automatic_expiry_enabled": false
}
},
"native_application_recovery_verified": false
}

View file

@ -0,0 +1,53 @@
# Coulomb recovery API custody
Owner: railiance-platform / platform-root. Admission decisions
27bbc1ac-e275-42be-ba34-6cf16eae4e78 and 6139e02b-3fb7-4eff-be8a-efe127c45ce5.
Non-secret coordinates: coulomb-recovery-api.json. Native evidence:
../evidence/2026-10-29-coulomb-recovery-api-bootstrap.json.
Routine access uses separate reader/custodian API pairs under an owner-private
directory outside Git, normally ~/.config/railiance-platform/coulomb-social-recovery/.
The worker holds only its original publisher pair and the dedicated public age
recipient. Never deliver the custodian pair, reader pair or private age identity
to that worker. No sibling credentials or private keys are reused.
Check independent retrieval without writing a private identity:
```sh
python3 scripts/application_recovery_access.py --execute --material age
```
For an isolated attended restore, add --output with a fresh absolute filename
under an existing owner-private directory outside Git. The helper validates exact
project/name/protection/revision/nonexpiry and public recipient before writing
mode0600. Materials reader-pair and custodian-pair use the same front door;
omit --output to verify retrieval without creating another secret copy.
No value goes to stdout, Git, State Hub, shell arguments or environment.
The reader performs only prefix/version reads and listing in the isolated project.
The custodian can also publish new kit versions and read the dedicated escrow;
neither can delete retained versions or administer buckets/IAM. Scaleway's current
2023-04-17 bucket policies intersect IAM with an explicit allowlist. Deletion is
absent while publisher multipart abort is included; native checks prove both.
Negative PUT probes use separate transports because a denied upload can leave
the provider connection unusable for its next request.
Both buckets are private and versioned; no automatic expiry has been enabled.
The protected bucket never participates in rolling expiry. Rolling retention,
capacity, first coherent app capture, independent exact-version decryption and
isolated application recovery, monitoring and timers remain WP-0053/CSOC-WP-0012
acceptance work. Synthetic fixtures are boundary evidence, not app backups.
The routine pairs and age identity each have a separate protected, enabled,
nonexpiring provider secret version. They survive node/workstation loss. If all
local routine credentials are lost, platform-root uses its existing independent
account/MFA recovery to retrieve only the custodian escrow coordinate in the
public contract, then returns to the API front door. Emergency owner recovery is
separate from routine drill access; preserve the platform-root recovery mechanism.
Routine API keys expire on 2027-10-28; exact timestamps are in the JSON contract.
Platform-root owns renewal and independently read-back escrow before those
deadlines, using a bounded attended construction window. No standing organization
administration key or publisher IAM administration is admitted. The construction
key was revoked, its temporary pair removed and the personal browser context
closed without saving state. Routine drills do not rerun identity bootstrap.

View file

@ -0,0 +1,445 @@
{
"programmatic_direction_reference": "6139e02b-3fb7-4eff-be8a-efe127c45ce5",
"applications": {
"bootstrap": "2a355842-e03b-42a3-8af7-6cd8f8b98bcd",
"custodian": "f80037a2-87c9-44d2-9163-3e6907af3ced",
"reader": "7a4055fc-a3f5-40bf-8013-cd0eec9028de"
},
"automatic_expiry_enabled": false,
"bootstrap_key_revoked_verified": true,
"buckets": {
"railiance-coulomb-social-archives": {
"created": true,
"lifecycle_rules": [],
"policy": {
"Id": "coulomb-independent-recovery",
"Statement": [
{
"Action": "s3:*",
"Effect": "Allow",
"Principal": {
"SCW": "user_id:3d029efb-4f70-4f82-a3bb-cefbe255232b"
},
"Resource": [
"railiance-coulomb-social-archives",
"railiance-coulomb-social-archives/*"
],
"Sid": "PlatformOwner"
},
{
"Action": "s3:*",
"Effect": "Allow",
"Principal": {
"SCW": "application_id:2a355842-e03b-42a3-8af7-6cd8f8b98bcd"
},
"Resource": [
"railiance-coulomb-social-archives",
"railiance-coulomb-social-archives/*"
],
"Sid": "TemporaryConstruction"
},
{
"Action": [
"s3:GetObject",
"s3:GetObjectVersion"
],
"Effect": "Allow",
"Principal": {
"SCW": "application_id:7a4055fc-a3f5-40bf-8013-cd0eec9028de"
},
"Resource": "railiance-coulomb-social-archives/archives/*",
"Sid": "readerObjects"
},
{
"Action": [
"s3:ListBucket",
"s3:ListBucketVersions"
],
"Condition": {
"StringLike": {
"s3:prefix": [
"archives/",
"archives/*"
]
}
},
"Effect": "Allow",
"Principal": {
"SCW": "application_id:7a4055fc-a3f5-40bf-8013-cd0eec9028de"
},
"Resource": "railiance-coulomb-social-archives",
"Sid": "readerList"
},
{
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:PutObject"
],
"Effect": "Allow",
"Principal": {
"SCW": "application_id:f80037a2-87c9-44d2-9163-3e6907af3ced"
},
"Resource": "railiance-coulomb-social-archives/archives/*",
"Sid": "custodianObjects"
},
{
"Action": [
"s3:ListBucket",
"s3:ListBucketVersions"
],
"Condition": {
"StringLike": {
"s3:prefix": [
"archives/",
"archives/*"
]
}
},
"Effect": "Allow",
"Principal": {
"SCW": "application_id:f80037a2-87c9-44d2-9163-3e6907af3ced"
},
"Resource": "railiance-coulomb-social-archives",
"Sid": "custodianList"
},
{
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:PutObject",
"s3:AbortMultipartUpload",
"s3:ListMultipartUploadParts"
],
"Effect": "Allow",
"Principal": {
"SCW": "application_id:681d00bf-b965-4323-b657-97bfde423511"
},
"Resource": "railiance-coulomb-social-archives/archives/*",
"Sid": "publisherObjects"
},
{
"Action": [
"s3:ListBucket",
"s3:ListBucketVersions"
],
"Condition": {
"StringLike": {
"s3:prefix": [
"archives/",
"archives/*"
]
}
},
"Effect": "Allow",
"Principal": {
"SCW": "application_id:681d00bf-b965-4323-b657-97bfde423511"
},
"Resource": "railiance-coulomb-social-archives",
"Sid": "publisherList"
},
{
"Action": [
"s3:GetBucketLocation",
"s3:GetBucketVersioning",
"s3:GetLifecycleConfiguration"
],
"Effect": "Allow",
"Principal": {
"SCW": [
"application_id:7a4055fc-a3f5-40bf-8013-cd0eec9028de",
"application_id:f80037a2-87c9-44d2-9163-3e6907af3ced",
"application_id:681d00bf-b965-4323-b657-97bfde423511"
]
},
"Resource": "railiance-coulomb-social-archives",
"Sid": "ArchiveMetadata"
}
],
"Version": "2023-04-17"
},
"public_acl_absent": true,
"versioning": "Enabled"
},
"railiance-coulomb-social-recovery": {
"created": true,
"lifecycle_rules": [],
"policy": {
"Id": "coulomb-independent-recovery",
"Statement": [
{
"Action": "s3:*",
"Effect": "Allow",
"Principal": {
"SCW": "user_id:3d029efb-4f70-4f82-a3bb-cefbe255232b"
},
"Resource": [
"railiance-coulomb-social-recovery",
"railiance-coulomb-social-recovery/*"
],
"Sid": "PlatformOwner"
},
{
"Action": "s3:*",
"Effect": "Allow",
"Principal": {
"SCW": "application_id:2a355842-e03b-42a3-8af7-6cd8f8b98bcd"
},
"Resource": [
"railiance-coulomb-social-recovery",
"railiance-coulomb-social-recovery/*"
],
"Sid": "TemporaryConstruction"
},
{
"Action": [
"s3:GetObject",
"s3:GetObjectVersion"
],
"Effect": "Allow",
"Principal": {
"SCW": "application_id:7a4055fc-a3f5-40bf-8013-cd0eec9028de"
},
"Resource": "railiance-coulomb-social-recovery/kits/*",
"Sid": "readerObjects"
},
{
"Action": [
"s3:ListBucket",
"s3:ListBucketVersions"
],
"Condition": {
"StringLike": {
"s3:prefix": [
"kits/",
"kits/*"
]
}
},
"Effect": "Allow",
"Principal": {
"SCW": "application_id:7a4055fc-a3f5-40bf-8013-cd0eec9028de"
},
"Resource": "railiance-coulomb-social-recovery",
"Sid": "readerList"
},
{
"Action": [
"s3:GetBucketLocation",
"s3:GetBucketVersioning",
"s3:GetLifecycleConfiguration"
],
"Effect": "Allow",
"Principal": {
"SCW": "application_id:7a4055fc-a3f5-40bf-8013-cd0eec9028de"
},
"Resource": "railiance-coulomb-social-recovery",
"Sid": "readerMetadata"
},
{
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:PutObject"
],
"Effect": "Allow",
"Principal": {
"SCW": "application_id:f80037a2-87c9-44d2-9163-3e6907af3ced"
},
"Resource": "railiance-coulomb-social-recovery/kits/*",
"Sid": "custodianObjects"
},
{
"Action": [
"s3:ListBucket",
"s3:ListBucketVersions"
],
"Condition": {
"StringLike": {
"s3:prefix": [
"kits/",
"kits/*"
]
}
},
"Effect": "Allow",
"Principal": {
"SCW": "application_id:f80037a2-87c9-44d2-9163-3e6907af3ced"
},
"Resource": "railiance-coulomb-social-recovery",
"Sid": "custodianList"
},
{
"Action": [
"s3:GetBucketLocation",
"s3:GetBucketVersioning",
"s3:GetLifecycleConfiguration"
],
"Effect": "Allow",
"Principal": {
"SCW": "application_id:f80037a2-87c9-44d2-9163-3e6907af3ced"
},
"Resource": "railiance-coulomb-social-recovery",
"Sid": "custodianMetadata"
}
],
"Version": "2023-04-17"
},
"public_acl_absent": true,
"versioning": "Enabled"
}
},
"completed_at": "2026-10-29T20:59:12.852425+00:00",
"decision": "27bbc1ac-e275-42be-ba34-6cf16eae4e78",
"native_application_recovery_verified": false,
"native_checks": {
"archives_custodian_delete": {
"denied": true,
"http_status": 403
},
"archives_custodian_outside_prefix": {
"denied": true,
"http_status": 403
},
"archives_custodian_policy_write": {
"denied": true,
"http_status": 403
},
"archives_publisher_delete": {
"denied": true,
"http_status": 403
},
"archives_publisher_outside_prefix": {
"denied": true,
"http_status": 403
},
"archives_publisher_policy_write": {
"denied": true,
"http_status": 403
},
"archives_reader_delete": {
"denied": true,
"http_status": 403
},
"archives_reader_outside_prefix": {
"denied": true,
"http_status": 403
},
"archives_reader_policy_write": {
"denied": true,
"http_status": 403
},
"archives_reader_put": {
"denied": true,
"http_status": 403
},
"archives_reader_version_get_hash": {
"verified": true,
"version_id": "1793307392673579"
},
"custodian_iam_admin": {
"denied": true,
"http_status": 403
},
"kits_custodian_delete": {
"denied": true,
"http_status": 403
},
"kits_custodian_outside_prefix": {
"denied": true,
"http_status": 403
},
"kits_custodian_policy_write": {
"denied": true,
"http_status": 403
},
"kits_publisher_delete": {
"denied": true,
"http_status": 403
},
"kits_publisher_outside_prefix": {
"denied": true,
"http_status": 403
},
"kits_publisher_policy_write": {
"denied": true,
"http_status": 403
},
"kits_reader_delete": {
"denied": true,
"http_status": 403
},
"kits_reader_outside_prefix": {
"denied": true,
"http_status": 403
},
"kits_reader_policy_write": {
"denied": true,
"http_status": 403
},
"kits_reader_put": {
"denied": true,
"http_status": 403
},
"kits_reader_version_get_hash": {
"verified": true,
"version_id": "1793307384956710"
},
"publisher_create_readback": {
"verified": true
},
"publisher_escrow": {
"denied": true,
"http_status": 403
},
"publisher_iam_admin": {
"denied": true,
"http_status": 403
},
"publisher_own_multipart_abort": {
"verified": true
},
"publisher_protected_kit_get": {
"denied": true,
"http_status": 403
},
"reader_escrow": {
"denied": true,
"http_status": 403
},
"reader_iam_admin": {
"denied": true,
"http_status": 403
}
},
"organization_wide_grants": false,
"personal_browser_context_closed": true,
"personal_state_saved": false,
"private_values_printed": false,
"project_id": "06d107bc-9d84-4672-b2a0-95701cc0c07f",
"project_only_policies_verified": 4,
"protected_secret_references": {
"coulomb-social-age-recovery": {
"id": "634e4b9f-0b61-4329-a83c-1ed0e76c4636",
"revision": 1
},
"coulomb-social-recovery-access-canary": {
"id": "db825503-cf12-4bfd-8cc5-f16d09edd8b5",
"revision": 1
},
"coulomb-social-recovery-custodian-api": {
"id": "cf44e9bd-9edc-450b-9f10-564ee3008305",
"revision": 1
},
"coulomb-social-recovery-reader-api": {
"id": "241742f7-d3b5-4163-8d87-3a3d9585778d",
"revision": 1
}
},
"public_recipient": "age1qm30jk8q0cezey652dk2dhcr3d9vs528v6lg8mavl6d4q3e3vgnqmrmyy3",
"publisher_pair_replaced": false,
"routine_age_and_both_pairs_retrieved_without_personal_session": true,
"schema": "platform.coulomb-recovery-bootstrap.v1",
"temporary_pair_removed": true,
"timers_activated": false
}

View file

@ -0,0 +1,89 @@
"""Routine Coulomb recovery access; scoped custodian API, no Console session."""
from __future__ import annotations
import argparse
import base64
import json
import os
import sys
from pathlib import Path
from application_recovery_identities import Refused, private_directory, private_json
from application_recovery_resources import API, SECRET_BASE, public_recipient, status
CONTRACT = Path(__file__).resolve().parents[1] / "docs/credential-lane-designs/coulomb-recovery-api.json"
PROJECT = "06d107bc-9d84-4672-b2a0-95701cc0c07f"
def retrieve(api, contract, material):
if (contract.get("schema") != "platform.coulomb-recovery-api.v1"
or contract.get("project_id") != PROJECT):
raise Refused("exact_coulomb_contract_required")
reference = contract["materials"][material]
path = SECRET_BASE + "/" + reference["id"]
metadata = api("GET", path)
if (metadata.get("id") != reference["id"] or metadata.get("name") != reference["name"]
or metadata.get("project_id") != PROJECT or metadata.get("protected") is not True
or metadata.get("type") != "opaque" or metadata.get("ephemeral_policy") is not None
or metadata.get("deletion_requested_at") is not None):
raise Refused("protected_exact_escrow_required")
version = api("GET", path + "/versions/" + str(reference["revision"]))
properties = version.get("ephemeral_properties") or {}
if (version.get("status") != "enabled" or properties.get("expires_at")
or properties.get("expires_once_accessed")):
raise Refused("enabled_nonexpiring_exact_version_required")
response = api("GET", path + "/versions/" + str(reference["revision"]) + "/access")
if response.get("secret_id") != reference["id"] or response.get("revision") != reference["revision"]:
raise Refused("escrow_response_binding_refused")
payload = base64.b64decode(response["data"], validate=True)
if material == "age":
if public_recipient(payload) != contract["public_recipient"]:
raise Refused("public_recipient_differs")
else:
pair = json.loads(payload)
if set(pair) != {"AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"} or any(
not isinstance(v, str) or not v or "\n" in v for v in pair.values()
):
raise Refused("exact_api_pair_required")
return payload
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--execute", action="store_true")
parser.add_argument("--directory", type=Path, default=Path.home() / ".config/railiance-platform/coulomb-social-recovery")
parser.add_argument("--material", choices=("age", "reader-pair", "custodian-pair"), default="age")
parser.add_argument("--output", type=Path)
args = parser.parse_args()
if not args.execute:
print(json.dumps({"status": "preview", "material": args.material, "provider_contacted": False,
"personal_login_required": False}))
return
private_directory(args.directory)
if args.output:
if not args.output.is_absolute():
raise Refused("absolute_private_output_required")
private_directory(args.output.parent)
if args.output.exists() or args.output.is_symlink():
raise Refused("fresh_private_output_required")
contract = json.loads(CONTRACT.read_text())
pair = private_json(args.directory / "custodian-pair.json")
payload = retrieve(API(pair), contract, args.material)
if args.output:
fd = os.open(args.output, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600)
with os.fdopen(fd, "wb") as stream:
stream.write(payload)
stream.flush()
os.fsync(stream.fileno())
print(json.dumps({"status": "scoped_api_retrieval_verified", "material": args.material,
"private_output_created": bool(args.output), "credential_values_printed": False,
"personal_session_used": False}))
if __name__ == "__main__":
try:
main()
except Exception as error: # noqa: BLE001 -- suppress secret-bearing provider diagnostics
print(json.dumps({"status": "refused", "failure_type": type(error).__name__,
"native_status": status(error)}))
sys.exit(1)

View file

@ -7,6 +7,7 @@ from __future__ import annotations
import argparse
import base64
import fcntl
import hashlib
import hmac
import json
@ -180,6 +181,16 @@ class Resources:
def save(self):
checkpoint(self.path, self.state)
def deny_s3(self, role, operation, **arguments):
# Some denied PUTs leave a provider keep-alive connection unusable for
# the next request (observed HTTP400 with an empty error). Isolate each
# negative probe so it cannot corrupt subsequent positive read proof.
client = s3(self.pairs[role], self.project)
try:
return denied(lambda: getattr(client, operation)(**arguments))
finally:
client.close()
def mutate(self, label, call):
self.state["pending"] = label
self.save()
@ -360,21 +371,20 @@ class Resources:
raise Refused("independent_version_listing_required")
proofs[prefix + "_reader_version_get_hash"] = {"verified": True, "version_id": version}
for role in ("reader", "custodian", "publisher"):
client = self.clients[role]
# All deletion targets are newly made synthetic canaries. No
# actual retained backup is ever a destructive negative probe.
proofs[prefix + "_" + role + "_delete"] = denied(lambda client=client, bucket=bucket, key=key, version=version: client.delete_object(
Bucket=bucket, Key=key, VersionId=version))
proofs[prefix + "_" + role + "_delete"] = self.deny_s3(role, "delete_object",
Bucket=bucket, Key=key, VersionId=version)
intended = self.state["buckets"][bucket]["policy"]
proofs[prefix + "_" + role + "_policy_write"] = denied(lambda client=client, bucket=bucket, intended=intended: client.put_bucket_policy(
Bucket=bucket, Policy=json.dumps(intended)))
proofs[prefix + "_" + role + "_outside_prefix"] = denied(lambda client=client, bucket=bucket: client.get_object(
Bucket=bucket, Key="outside-approved-prefix/synthetic-absent"))
proofs[prefix + "_reader_put"] = denied(lambda reader=reader, bucket=bucket, prefix=prefix: reader.put_object(
Bucket=bucket, Key=prefix + "/reader-write-denial.txt", Body=b"synthetic-only"))
proofs[prefix + "_" + role + "_policy_write"] = self.deny_s3(role, "put_bucket_policy",
Bucket=bucket, Policy=json.dumps(intended))
proofs[prefix + "_" + role + "_outside_prefix"] = self.deny_s3(role, "get_object",
Bucket=bucket, Key="outside-approved-prefix/synthetic-absent")
proofs[prefix + "_reader_put"] = self.deny_s3("reader", "put_object",
Bucket=bucket, Key=prefix + "/reader-write-denial.txt", Body=b"synthetic-only")
kit = self.state["fixtures"]["kits"]
proofs["publisher_protected_kit_get"] = denied(lambda: self.clients["publisher"].get_object(
Bucket=kit["bucket"], Key=kit["key"], VersionId=kit["version_id"]))
proofs["publisher_protected_kit_get"] = self.deny_s3("publisher", "get_object",
Bucket=kit["bucket"], Key=kit["key"], VersionId=kit["version_id"])
publisher = self.clients["publisher"]
# Verify ordinary worker upload/readback in addition to its multipart
# abort. No content is captured from the application by this helper.
@ -425,7 +435,11 @@ def main():
return
import uuid
uuid.UUID(args.owner_user_id)
print(json.dumps(Resources(args.directory, args.owner_user_id).run()))
private_directory(args.directory)
fd = os.open(args.directory / "resource-bootstrap.lock", os.O_WRONLY | os.O_CREAT | os.O_NOFOLLOW, 0o600)
with os.fdopen(fd, "w") as lock:
fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
print(json.dumps(Resources(args.directory, args.owner_user_id).run()))
if __name__ == "__main__":

View file

@ -0,0 +1,67 @@
"""Synthetic access refusals; no live API or private custody values."""
import base64
import copy
import importlib.util
import sys
import unittest
from pathlib import Path
SCRIPTS = Path(__file__).resolve().parents[1] / "scripts"
sys.path.insert(0, str(SCRIPTS))
spec = importlib.util.spec_from_file_location("access", SCRIPTS / "application_recovery_access.py")
m = importlib.util.module_from_spec(spec)
spec.loader.exec_module(m)
class AccessTests(unittest.TestCase):
def setUp(self):
self.contract = {"schema": "platform.coulomb-recovery-api.v1", "project_id": m.PROJECT,
"materials": {"reader-pair": {"id": "synthetic-id", "name": "synthetic-name", "revision": 1}}}
self.metadata = {"id": "synthetic-id", "name": "synthetic-name", "project_id": m.PROJECT,
"protected": True, "type": "opaque", "ephemeral_policy": None}
self.version = {"status": "enabled", "ephemeral_properties": {}}
self.accesses = 0
def api(self, method, path):
self.assertEqual(method, "GET")
if path.endswith("/access"):
self.accesses += 1
return {"secret_id": "synthetic-id", "revision": 1, "data": base64.b64encode(
b'{"AWS_ACCESS_KEY_ID":"SYNTHETIC_ID","AWS_SECRET_ACCESS_KEY":"SYNTHETIC_VALUE"}').decode()}
if "/versions/" in path:
return self.version
return self.metadata
def test_routine_retrieval_uses_only_protected_bound_scoped_secret(self):
payload = m.retrieve(self.api, self.contract, "reader-pair")
self.assertIn(b"SYNTHETIC_ID", payload)
self.assertEqual(self.accesses, 1)
def test_project_name_protection_type_and_expiry_drift_refuse_before_data(self):
baseline = copy.deepcopy(self.metadata)
for key, value in (("project_id", "foreign"), ("name", "foreign"), ("protected", False),
("type", "certificate"), ("ephemeral_policy", {"time_to_live": "60s"}),
("deletion_requested_at", "synthetic-time")):
self.metadata = dict(baseline, **{key: value})
with self.assertRaises(m.Refused):
m.retrieve(self.api, self.contract, "reader-pair")
self.assertEqual(self.accesses, 0)
def test_disabled_or_expiring_version_refuses_before_data(self):
for version in ({"status": "disabled"}, {"status": "enabled", "ephemeral_properties": {"expires_at": "soon"}},
{"status": "enabled", "ephemeral_properties": {"expires_once_accessed": True}}):
self.version = version
with self.assertRaises(m.Refused):
m.retrieve(self.api, self.contract, "reader-pair")
self.assertEqual(self.accesses, 0)
def test_wrong_response_revision_refused(self):
def api(method, path):
result = self.api(method, path)
return dict(result, revision=2) if path.endswith("/access") else result
with self.assertRaises(m.Refused):
m.retrieve(api, self.contract, "reader-pair")
if __name__ == "__main__":
unittest.main()

View file

@ -3,6 +3,7 @@ import importlib.util
import sys
import unittest
from pathlib import Path
from unittest.mock import Mock, patch
SCRIPTS = Path(__file__).resolve().parents[1] / "scripts"
sys.path.insert(0, str(SCRIPTS))
@ -81,6 +82,16 @@ class ResourcesTests(unittest.TestCase):
returned["Statement"][0]["Action"].append("s3:DeleteObject")
self.assertNotEqual(m.canonical_policy(original), m.canonical_policy(returned))
def test_negative_probe_uses_and_closes_its_own_transport(self):
resource = object.__new__(m.Resources)
resource.pairs, resource.project = {"reader": {}}, "synthetic-project"
client = Mock()
client.put_object.side_effect = m.NativeError(403)
with patch.object(m, "s3", return_value=client) as factory:
self.assertTrue(resource.deny_s3("reader", "put_object", Bucket="synthetic")["denied"])
factory.assert_called_once_with({}, "synthetic-project")
client.close.assert_called_once()
if __name__ == "__main__":
unittest.main()

View file

@ -8,7 +8,7 @@ status: active
owner: codex
topic_slug: coulomb-social
created: "2026-10-07"
updated: "2026-10-28"
updated: "2026-10-29"
state_hub_workstream_id: "cb55e474-c7a5-5c6f-bd72-ce65f853e3e3"
---
@ -354,3 +354,50 @@ retires construction authority and logs out on finish. It saves no personal
browser state. Run --preflight-only first; routine access uses the scoped API
pairs, never that personal session. The expired earlier capture is not a
credential lane. Existing independent recovery and service gates stay open.
## Native scoped API custody established — 2026-10-29
The attended bootstrap created isolated project
06d107bc-9d84-4672-b2a0-95701cc0c07f, three dedicated applications and four
verified project-only policies. No organization-wide grant or publisher-pair
replacement. The two-hour construction key expired during an approval pause;
the refreshed existing browser revoked that exact expired key and issued only
its bounded replacement. Reader/custodian pairs were preserved.
Two private versioned buckets now have owner-preserving allowlists. No lifecycle
expiry is enabled. Four protected nonexpiring secrets contain a synthetic access
canary, the dedicated age identity, reader pair and custodian pair. Native
custodian API readback equals all three real values; publisher/reader canary
access denies403. Thirty native checks include exact-version/hash/list reads,
publisher create/readback/own multipart abort, denied retained-version deletion,
policy administration, outside-prefix reads, protected-kit access by publisher,
reader writes and IAM administration. Only newly created synthetic objects were
used as destructive denial targets. No production capture, restore or timer.
The construction key was revoked with native GET404 verification and its own
temporary pair removed. Personal context closed; no browser state saved. Routine
scripts/application_recovery_access.py independently retrieves/validates age and
both API pairs without personal login. Public contract and recovery procedure:
docs/credential-lane-designs/coulomb-recovery-api.{json,md}; receipt:
docs/evidence/2026-10-29-coulomb-recovery-api-bootstrap.json. Twenty-six synthetic
tests and targeted Ruff pass. Future routine keys expire2027-10-28; platform-root
owns renewal/read-back escrow before those recorded deadlines.
Native corrections were narrow: respect the provider's ten-statement policy
limit, compare every policy field independent of array order, and isolate each
negative PUT transport from positive reads. No permission was broadened to make
a denial pass. T02 remains progress for full kit/last recovered app point,
retention/capacity and historical-copy disposition; T03/T04 remain open for first
application recovery and monitored scheduling. Earlier unperformed statements
above describe their dated preparation stage.
Consumer delivered only the verified public recipient to the admitted worker's
root-owned0600 recipient.env with cluster UID/installed guard hash/readback checks.
Private age identity and recovery pairs remain outside the worker. Consumer
receipt: docs/release/backup-public-recipient-delivery-2026-10-29.json.
Publication preflight classified the receipt's access-direction decision UUID
as generic-api-key because of its metadata field name. The exact finding was
line2, containing only the already public approval reference. Renamed that field
to programmatic_direction_reference; no scanner rule, ignore or bypass changed.
Only unpublished commits are amended; published history is preserved.