diff --git a/credential-change-requests/CCR-2026-0016-glas-claude-anthropic.yaml b/credential-change-requests/CCR-2026-0016-glas-claude-anthropic.yaml index 3b75d33..97cdefe 100644 --- a/credential-change-requests/CCR-2026-0016-glas-claude-anthropic.yaml +++ b/credential-change-requests/CCR-2026-0016-glas-claude-anthropic.yaml @@ -10,11 +10,16 @@ in_flight: missing_fields: - openbao.policy_file - openbao.auth - blocking_reason: Anthropic organization and workspace budget await user input; the sandbox owner machine identity and protected delivery path have not been verified. No live grant or key exists from this request. + blocking_reason: Provider organization, key name and expiration supplied by user. + Empty-only KV seed authorized for operator UI handoff; live custody and the sandbox + owner machine identity/delivery remain unverified. Workspace scope and budget + are not confirmed. owner: railiance-platform requester: agent: codex - reason: User selected a dedicated Anthropic workload API key for GLAS-WP-0012 and SAND-WP-0015. Establish custody and owner delivery before the real local Claude proof. + reason: User selected a dedicated Anthropic workload API key for GLAS-WP-0012 and + SAND-WP-0015. Establish custody and owner delivery before the real local Claude + proof. review: required: true required_approvers: @@ -24,13 +29,21 @@ review: - at: '2026-09-05' reviewer: user via chat decision: authentication_model_selected - comment: User requested establishment of an Anthropic workload API key. This records the chosen authentication model; final machine bindings are not yet known. + comment: User requested establishment of an Anthropic workload API key. This records + the chosen authentication model; final machine bindings are not yet known. + - at: '2026-09-05' + reviewer: user via chat + decision: empty_seed_authorized + comment: User authorized preparing the existing proposed location with an empty + version; user will create a version containing the secret through the OpenBao + UI. No runtime grant authorized by this seed. target: domain: infotech tenant: glas-harness workload: sand-boxer-claude-agent-dev environment: production - purpose: Dedicated Claude Code inference for the Glas local agent-dev profile, delivered by the sandbox owner. + purpose: Dedicated Claude Code inference for the Glas local agent-dev profile, delivered + by the sandbox owner. openbao: mount: platform kv_path: platform/workloads/glas-harness/claude-agent-dev @@ -46,34 +59,71 @@ access_frontdoor: resolvable: false delivery: surface: owner-exec - target: Sand-boxer delivers ANTHROPIC_API_KEY only to the selected Claude workload; neither the Glas caller nor the runtime receives an OpenBao token. + target: Sand-boxer delivers ANTHROPIC_API_KEY only to the selected Claude workload; + neither the Glas caller nor the runtime receives an OpenBao token. risk: classification: high notes: - - Proposed KV coordinates and catalog selector are reserved design names, not surveyed live objects. - - Provider credential can incur API charges; use a dedicated workspace and user-selected budget. - - Use a workspace-scoped service account key; organization administration is outside the workload grant. - - OpenBao token expiration does not expire the provider key. Provider revocation is required for compromise. - - Owner environment injection can expose the key to descendants within that workload; it is not per-process secrecy against workload code. + - Proposed KV coordinates and catalog selector are reserved design names, not surveyed + live objects. + - Provider credential can incur API charges; use a dedicated workspace and user-selected + budget. + - Use a workspace-scoped service account key; organization administration is outside + the workload grant. + - OpenBao token expiration does not expire the provider key. Provider revocation + is required for compromise. + - Owner environment injection can expose the key to descendants within that workload; + it is not per-process secrecy against workload code. verification: positive: - - Confirm provider organization, workspace, service account, key identifier and expiration using metadata only. - - Exact authenticated sandbox owner can read only the intended data entry and deliver the field without logging it. - - Bounded real Claude proof succeeds through enforced provider egress and removes private state on teardown. + - Confirm provider organization, workspace, service account, key identifier and + expiration using metadata only. + - Exact authenticated sandbox owner can read only the intended data entry and deliver + the field without logging it. + - Bounded real Claude proof succeeds through enforced provider egress and removes + private state on teardown. negative: - - Wrong owner identity, sibling KV path, metadata read, parent listing and workload writes are denied. + - Wrong owner identity, sibling KV path, metadata read, parent listing and workload + writes are denied. - Generic coding-agent identity cannot retrieve the credential directly. - - No credential or OpenBao token appears in execution replies, artifacts, source tree or State Hub. + - No credential or OpenBao token appears in execution replies, artifacts, source + tree or State Hub. - A revoked predecessor provider key fails authentication after controlled rotation. activation_conditions: - - User confirms Anthropic organization and workspace budget; provider service account and key are created through attended Console custody. - - Confirm actual sandbox host service identity and auth binding; review exact read policy and separate protected custody writer before apply. - - Seed KV with compare-and-set zero through attended custody; never enter values in chat or command arguments. - - Positive and negative access, owner delivery and provider authentication evidence pass before route activation. + - User confirms Anthropic organization and workspace budget; provider service account + and key are created through attended Console custody. + - Confirm actual sandbox host service identity and auth binding; review exact read + policy and separate protected custody writer before apply. + - Seed KV with compare-and-set zero through attended custody; never enter values + in chat or command arguments. + - Positive and negative access, owner delivery and provider authentication evidence + pass before route activation. + evidence: + - at: '2026-09-05' + actor: codex + kind: empty_seed + result: passed + details: + - Empty ANTHROPIC_API_KEY version 1 created with CAS zero; user will create version + 2 in UI. + - Request id 50cafc25-8d24-c1d6-5be8-1ade049e088b. + - Provider metadata recorded; metadata-only recovery completed after empty response + parsing fix; contained sessions revoked. + - No secret data read or real key handled; runtime lane remains inactive. lifecycle: - deactivate: Disable the owner route and provider key; revoke outstanding OpenBao reader tokens. Preserve KV history under platform retention rules. - rotate: Create a replacement provider key, write with expected-version CAS, stop old runs, verify new delivery and inference, then revoke the predecessor at Anthropic and prove its denial. - compromised: Disable the provider key immediately, stop affected runs and owner route, revoke Bao leases, replace forward through protected custody and record non-secret incident evidence. + deactivate: Disable the owner route and provider key; revoke outstanding OpenBao + reader tokens. Preserve KV history under platform retention rules. + rotate: Create a replacement provider key, write with expected-version CAS, stop + old runs, verify new delivery and inference, then revoke the predecessor at Anthropic + and prove its denial. + compromised: Disable the provider key immediately, stop affected runs and owner + route, revoke Bao leases, replace forward through protected custody and record + non-secret incident evidence. state_hub: workplan_id: GLAS-WP-0012 task_id: GLAS-WP-0012-T02 +provider_metadata: + organization_id: e1a8f305-9e64-4639-a7fd-af48e34f37c7 + key_name: claude_key_bernd.worsch + expires_at: '2027-01-31T21:00:00Z' + source: user supplied; provider identity and workspace scope not independently verified diff --git a/scripts/prepare-glas-anthropic.py b/scripts/prepare-glas-anthropic.py new file mode 100644 index 0000000..02afc48 --- /dev/null +++ b/scripts/prepare-glas-anthropic.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +"""User-authorized empty KV seed for CCR-2026-0016; silent OIDC child.""" +import json +from pathlib import Path +import subprocess +import sys + +DATA_PATH = 'platform/data/workloads/glas-harness/claude-agent-dev' +META_PATH = 'platform/metadata/workloads/glas-harness/claude-agent-dev' +RECEIPT = Path('/tmp/glas-anthropic-empty-receipt.json') + +def bao(*args, payload=None): + r = subprocess.run(['bao', *args], input=None if payload is None else json.dumps(payload), + text=True, capture_output=True, timeout=30) + if r.returncode: + raise RuntimeError('bao_operation_failed') + return json.loads(r.stdout) if r.stdout.strip() else {} + +def main(): + if sys.argv[1:] == ['--complete-metadata']: + receipt = json.loads(RECEIPT.read_text()) + if receipt.get('path') != DATA_PATH or receipt.get('version') != 1: + raise RuntimeError('invalid_receipt') + observed = bao('read', '-format=json', META_PATH)['data'] + if observed.get('current_version', 0) < 1: + raise RuntimeError('missing_seed') + elif not sys.argv[1:]: + # CAS zero makes concurrent creation and existing versions refuse; no data GET. + result = bao('write', '-format=json', DATA_PATH, '-', + payload={'options': {'cas': 0}, 'data': {'ANTHROPIC_API_KEY': ''}}) + version = result['data']['version'] + receipt = {'ccr': 'CCR-2026-0016', 'path': DATA_PATH, 'version': version, + 'empty_seed_created': True, 'metadata_written': False, + 'request_id': result.get('request_id')} + with RECEIPT.open('x') as f: + json.dump(receipt, f) + else: + raise RuntimeError('invalid_arguments') + # Only non-secret custom metadata. No secret expiry is enforced by KV metadata. + bao('write', '-format=json', META_PATH, '-', payload={'custom_metadata': { + 'ccr': 'CCR-2026-0016', 'custody_owner': 'railiance-platform', + 'provider': 'anthropic', 'organization_id': 'e1a8f305-9e64-4639-a7fd-af48e34f37c7', + 'provider_key_name': 'claude_key_bernd.worsch', + 'provider_expires_at': '2027-01-31T21:00:00Z', + 'seed_version': '1', 'seed_contains_secret': 'false', + 'handoff': 'operator creates next version in UI; runtime lane remains inactive'}}) + receipt['metadata_written'] = True + RECEIPT.write_text(json.dumps(receipt)) + +if __name__ == '__main__': + try: + main() + except Exception: + sys.exit(1) # contained executor must never return provider/client output