engineering-platform 2.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- engineering_platform/ENGINEERING_PLATFORM_CONFIG.json +32 -0
- engineering_platform/ENGINEERING_PLATFORM_VERSION.json +15 -0
- engineering_platform/__init__.py +1 -0
- engineering_platform/__main__.py +7 -0
- engineering_platform/agent_state.py +530 -0
- engineering_platform/agent_trust.py +174 -0
- engineering_platform/assets/dashboard.css +1317 -0
- engineering_platform/assets/dashboard.js +8534 -0
- engineering_platform/assets/dashboard_locales.mjs +4049 -0
- engineering_platform/assets/dashboard_status_store.mjs +41 -0
- engineering_platform/assets/operations-console/apple-touch-icon-dark.png +0 -0
- engineering_platform/assets/operations-console/apple-touch-icon-light.png +0 -0
- engineering_platform/assets/operations-console/icon-dark.png +0 -0
- engineering_platform/assets/operations-console/icon-light.png +0 -0
- engineering_platform/assets/operations-console/icon-transparent.png +0 -0
- engineering_platform/assets/operations-console/manifest.webmanifest +11 -0
- engineering_platform/capability_preflight.py +285 -0
- engineering_platform/capability_review.py +261 -0
- engineering_platform/central_data_transfer.py +195 -0
- engineering_platform/central_database.py +245 -0
- engineering_platform/central_store_migration.py +1672 -0
- engineering_platform/codex_capacity.py +81 -0
- engineering_platform/codex_chat.py +226 -0
- engineering_platform/codex_observability.py +153 -0
- engineering_platform/component_lock.py +40 -0
- engineering_platform/component_logging.py +420 -0
- engineering_platform/console_presentation.py +14 -0
- engineering_platform/console_route_ownership.py +83 -0
- engineering_platform/contracts/__init__.py +38 -0
- engineering_platform/contracts/ep_consumer.py +391 -0
- engineering_platform/contracts/models.py +105 -0
- engineering_platform/contracts/projection.py +401 -0
- engineering_platform/dashboard_browser_validation.py +206 -0
- engineering_platform/dashboard_state.py +630 -0
- engineering_platform/dashboard_supervisor.swift +105 -0
- engineering_platform/dashboard_translation.py +129 -0
- engineering_platform/dependabot_producer.py +349 -0
- engineering_platform/drift_diagnostics.py +144 -0
- engineering_platform/emergency_recovery.py +268 -0
- engineering_platform/engineering_memory.py +139 -0
- engineering_platform/ep_consumer_credentials.py +473 -0
- engineering_platform/evidence_projection.py +213 -0
- engineering_platform/execution_activity.py +218 -0
- engineering_platform/execution_context.py +132 -0
- engineering_platform/execution_errors.py +42 -0
- engineering_platform/execution_evidence.py +24 -0
- engineering_platform/execution_executor.py +730 -0
- engineering_platform/execution_finalization.py +44 -0
- engineering_platform/execution_host.py +3306 -0
- engineering_platform/execution_lease.py +365 -0
- engineering_platform/execution_lifecycle.py +447 -0
- engineering_platform/execution_models.py +43 -0
- engineering_platform/execution_readiness.py +166 -0
- engineering_platform/execution_reporting.py +1607 -0
- engineering_platform/execution_repository.py +253 -0
- engineering_platform/execution_timeout_policy.py +56 -0
- engineering_platform/execution_timing.py +440 -0
- engineering_platform/execution_transaction.py +28 -0
- engineering_platform/external_producer_binding.py +235 -0
- engineering_platform/file_inbox.py +249 -0
- engineering_platform/forensic_attribution.py +338 -0
- engineering_platform/forensic_attribution_v2.py +134 -0
- engineering_platform/forensic_delta.py +299 -0
- engineering_platform/golden_scenario.py +63 -0
- engineering_platform/historical_dashboard_configuration.py +171 -0
- engineering_platform/host_admin.py +199 -0
- engineering_platform/host_preflight.py +231 -0
- engineering_platform/installation_relocation.py +122 -0
- engineering_platform/investigation_ledger.py +89 -0
- engineering_platform/legacy_inbox_migration.py +79 -0
- engineering_platform/lifecycle_worker.py +223 -0
- engineering_platform/live_status.py +267 -0
- engineering_platform/local_api.py +209 -0
- engineering_platform/local_api_keychain.py +51 -0
- engineering_platform/local_repository_binding.py +138 -0
- engineering_platform/managed_autonomy.py +509 -0
- engineering_platform/managed_codex_runtime.py +105 -0
- engineering_platform/parity_context.py +203 -0
- engineering_platform/parity_lifecycle_dispatcher.py +488 -0
- engineering_platform/platform_admin.py +13 -0
- engineering_platform/platform_api.py +428 -0
- engineering_platform/platform_bootstrap.py +385 -0
- engineering_platform/platform_components.py +65 -0
- engineering_platform/platform_version.py +171 -0
- engineering_platform/pr_check_repair.py +276 -0
- engineering_platform/pr_evidence_backfill.py +278 -0
- engineering_platform/producer.py +209 -0
- engineering_platform/project_agent.py +366 -0
- engineering_platform/project_agent_service.py +244 -0
- engineering_platform/project_topology.py +126 -0
- engineering_platform/prompt_history.py +591 -0
- engineering_platform/provider_context.py +136 -0
- engineering_platform/provider_context_benchmark.py +41 -0
- engineering_platform/provider_context_scope.py +90 -0
- engineering_platform/provider_interruption.py +168 -0
- engineering_platform/provider_process_identity.py +80 -0
- engineering_platform/provider_readiness.py +138 -0
- engineering_platform/provider_recovery.py +647 -0
- engineering_platform/provider_usage.py +497 -0
- engineering_platform/providers.py +471 -0
- engineering_platform/qualification.py +220 -0
- engineering_platform/recommendation_handoff.py +238 -0
- engineering_platform/report_analysis.py +193 -0
- engineering_platform/repository_attachment.py +171 -0
- engineering_platform/repository_handoff.py +95 -0
- engineering_platform/resources.py +38 -0
- engineering_platform/reviewer_evidence.py +70 -0
- engineering_platform/schemas/repository-attachment.schema.json +61 -0
- engineering_platform/server.py +3679 -0
- engineering_platform/server_console_services.py +2024 -0
- engineering_platform/server_relay.py +172 -0
- engineering_platform/server_service.py +122 -0
- engineering_platform/status_model.py +135 -0
- engineering_platform/status_reconciliation.py +34 -0
- engineering_platform/storage.py +2440 -0
- engineering_platform/submission_cli.py +77 -0
- engineering_platform/submission_intake.py +45 -0
- engineering_platform/submission_service.py +317 -0
- engineering_platform/telemetry.py +951 -0
- engineering_platform/templates/workspace-config.json +25 -0
- engineering_platform/validation_identity.py +50 -0
- engineering_platform/validation_profile.py +211 -0
- engineering_platform/workspace_preflight.py +263 -0
- engineering_platform/worktree_provenance.py +147 -0
- engineering_platform/worktree_tooling.py +18 -0
- engineering_platform-2.2.0.dist-info/METADATA +18 -0
- engineering_platform-2.2.0.dist-info/RECORD +130 -0
- engineering_platform-2.2.0.dist-info/WHEEL +5 -0
- engineering_platform-2.2.0.dist-info/entry_points.txt +6 -0
- engineering_platform-2.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
"""Verifier-only Engineering Platform consumer credentials and qualification seam.
|
|
2
|
+
|
|
3
|
+
Increment 2a permits one short-lived, operator-created qualification credential.
|
|
4
|
+
It is not consumer registration or a general credential-issuance workflow.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
from collections.abc import Callable
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
from datetime import datetime, timedelta, timezone
|
|
13
|
+
import hashlib
|
|
14
|
+
import hmac
|
|
15
|
+
import json
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
import secrets
|
|
18
|
+
|
|
19
|
+
from .contracts.ep_consumer import RequestEnvelope
|
|
20
|
+
from .storage import open_storage
|
|
21
|
+
|
|
22
|
+
# These fixed predecessor domains preserve existing verifier and fingerprint
|
|
23
|
+
# values during the namespace migration. Renaming the domains would invalidate
|
|
24
|
+
# otherwise valid bearer credentials, so the opaque values are intentionally
|
|
25
|
+
# retained as migration compatibility material rather than current authority.
|
|
26
|
+
VERIFIER_DOMAIN = b"engineering-platform.local-api.verifier.v1\0"
|
|
27
|
+
FINGERPRINT_DOMAIN = b"engineering-platform.local-api.fingerprint.v1\0"
|
|
28
|
+
QUALIFICATION_PREFIX = "qualification-"
|
|
29
|
+
QUALIFICATION_TTL = timedelta(minutes=15)
|
|
30
|
+
PRODUCTION_PREFIX = "production-"
|
|
31
|
+
MAX_ACTIVE_PRODUCTION_CREDENTIALS = 2
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def verifier(credential: str) -> bytes:
|
|
35
|
+
return hashlib.sha256(VERIFIER_DOMAIN + credential.encode("ascii")).digest()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def fingerprint(credential: str) -> bytes:
|
|
39
|
+
return hashlib.sha256(FINGERPRINT_DOMAIN + credential.encode("ascii")).digest()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _timestamp(value: datetime) -> str:
|
|
43
|
+
return value.astimezone(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _scope(consumer_id: str, project_id: str) -> tuple[str, str]:
|
|
47
|
+
"""Reuse the v1 contract validator rather than duplicating identity rules."""
|
|
48
|
+
|
|
49
|
+
envelope = RequestEnvelope.parse(
|
|
50
|
+
{
|
|
51
|
+
"contract_version": "1.0",
|
|
52
|
+
"request_type": "contract.foundation",
|
|
53
|
+
"request_id": "qualification-credential",
|
|
54
|
+
"project_id": project_id,
|
|
55
|
+
"consumer": {"consumer_id": consumer_id},
|
|
56
|
+
"auth": {"scheme": "bearer", "credential": "operator-carrier"},
|
|
57
|
+
"payload": {},
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
return envelope.consumer.consumer_id, envelope.project_id
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass(frozen=True)
|
|
64
|
+
class CredentialScope:
|
|
65
|
+
consumer_id: str
|
|
66
|
+
project_id: str
|
|
67
|
+
verifier_value: bytes
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass(frozen=True)
|
|
71
|
+
class QualificationCredential:
|
|
72
|
+
credential_id: str
|
|
73
|
+
consumer_id: str
|
|
74
|
+
project_id: str
|
|
75
|
+
fingerprint_hex: str
|
|
76
|
+
created_at: str
|
|
77
|
+
expires_at: str
|
|
78
|
+
credential: str = field(repr=False)
|
|
79
|
+
|
|
80
|
+
def disclosure(self) -> dict[str, str]:
|
|
81
|
+
"""The sole plaintext handoff, used only by the create CLI command."""
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
"credential_id": self.credential_id,
|
|
85
|
+
"consumer_id": self.consumer_id,
|
|
86
|
+
"project_id": self.project_id,
|
|
87
|
+
"purpose": "QUALIFICATION",
|
|
88
|
+
"created_at": self.created_at,
|
|
89
|
+
"expires_at": self.expires_at,
|
|
90
|
+
"credential": self.credential,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def create_qualification_credential(
|
|
95
|
+
root: Path, *, consumer_id: str, project_id: str, now: datetime | None = None
|
|
96
|
+
) -> QualificationCredential:
|
|
97
|
+
"""Create the one active, short-lived qualification credential."""
|
|
98
|
+
|
|
99
|
+
consumer_id, project_id = _scope(consumer_id, project_id)
|
|
100
|
+
moment = now or datetime.now(timezone.utc)
|
|
101
|
+
created_at = _timestamp(moment)
|
|
102
|
+
expires_at = _timestamp(moment + QUALIFICATION_TTL)
|
|
103
|
+
credential = secrets.token_urlsafe(32)
|
|
104
|
+
credential_id = QUALIFICATION_PREFIX + secrets.token_hex(16)
|
|
105
|
+
candidate_verifier = verifier(credential)
|
|
106
|
+
candidate_fingerprint = fingerprint(credential)
|
|
107
|
+
connection = open_storage(root)
|
|
108
|
+
try:
|
|
109
|
+
active = connection.execute(
|
|
110
|
+
"SELECT 1 FROM ep_consumer_credentials WHERE credential_id LIKE ? "
|
|
111
|
+
"AND revoked_at IS NULL AND (expires_at IS NULL OR expires_at>CURRENT_TIMESTAMP) LIMIT 1",
|
|
112
|
+
(f"{QUALIFICATION_PREFIX}%",),
|
|
113
|
+
).fetchone()
|
|
114
|
+
if active is not None:
|
|
115
|
+
raise ValueError("An active qualification credential already exists; revoke it first.")
|
|
116
|
+
connection.execute(
|
|
117
|
+
"INSERT INTO ep_consumer_credentials(credential_id,consumer_id,project_id,verifier,fingerprint,issued_at,expires_at) "
|
|
118
|
+
"VALUES(?,?,?,?,?,?,?)",
|
|
119
|
+
(
|
|
120
|
+
credential_id,
|
|
121
|
+
consumer_id,
|
|
122
|
+
project_id,
|
|
123
|
+
candidate_verifier,
|
|
124
|
+
candidate_fingerprint,
|
|
125
|
+
created_at,
|
|
126
|
+
expires_at,
|
|
127
|
+
),
|
|
128
|
+
)
|
|
129
|
+
finally:
|
|
130
|
+
connection.close()
|
|
131
|
+
return QualificationCredential(
|
|
132
|
+
credential_id=credential_id,
|
|
133
|
+
consumer_id=consumer_id,
|
|
134
|
+
project_id=project_id,
|
|
135
|
+
fingerprint_hex=candidate_fingerprint.hex(),
|
|
136
|
+
created_at=created_at,
|
|
137
|
+
expires_at=expires_at,
|
|
138
|
+
credential=credential,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def qualification_status(root: Path) -> list[dict[str, str | bool | None]]:
|
|
143
|
+
"""Return safe, bounded qualification metadata without token material."""
|
|
144
|
+
|
|
145
|
+
connection = open_storage(root)
|
|
146
|
+
try:
|
|
147
|
+
rows = connection.execute(
|
|
148
|
+
"SELECT credential_id,consumer_id,project_id,fingerprint,issued_at,expires_at,revoked_at "
|
|
149
|
+
"FROM ep_consumer_credentials WHERE credential_id LIKE ? ORDER BY issued_at DESC",
|
|
150
|
+
(f"{QUALIFICATION_PREFIX}%",),
|
|
151
|
+
).fetchall()
|
|
152
|
+
finally:
|
|
153
|
+
connection.close()
|
|
154
|
+
now = _timestamp(datetime.now(timezone.utc))
|
|
155
|
+
return [
|
|
156
|
+
{
|
|
157
|
+
"credential_id": str(row[0]),
|
|
158
|
+
"consumer_id": str(row[1]),
|
|
159
|
+
"project_id": str(row[2]),
|
|
160
|
+
"fingerprint": bytes(row[3]).hex(),
|
|
161
|
+
"purpose": "QUALIFICATION",
|
|
162
|
+
"created_at": str(row[4]),
|
|
163
|
+
"expires_at": str(row[5]) if row[5] is not None else None,
|
|
164
|
+
"active": row[6] is None and (row[5] is None or str(row[5]) > now),
|
|
165
|
+
"revoked_at": str(row[6]) if row[6] is not None else None,
|
|
166
|
+
}
|
|
167
|
+
for row in rows
|
|
168
|
+
]
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def revoke_qualification_credential(root: Path, credential_id: str) -> bool:
|
|
172
|
+
"""Explicitly deactivate a qualification credential without deleting evidence."""
|
|
173
|
+
|
|
174
|
+
if not credential_id.startswith(QUALIFICATION_PREFIX):
|
|
175
|
+
raise ValueError("credential_id is not a qualification credential.")
|
|
176
|
+
connection = open_storage(root)
|
|
177
|
+
try:
|
|
178
|
+
result = connection.execute(
|
|
179
|
+
"UPDATE ep_consumer_credentials SET revoked_at=? WHERE credential_id=? AND revoked_at IS NULL",
|
|
180
|
+
(_timestamp(datetime.now(timezone.utc)), credential_id),
|
|
181
|
+
)
|
|
182
|
+
return result.rowcount == 1
|
|
183
|
+
finally:
|
|
184
|
+
connection.close()
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _registration(root: Path, consumer_id: str, project_id: str) -> tuple[str, ...] | None:
|
|
188
|
+
connection = open_storage(root)
|
|
189
|
+
try:
|
|
190
|
+
return connection.execute(
|
|
191
|
+
"SELECT consumer_id,project_id,status,created_at,updated_at,disabled_at,revoked_at "
|
|
192
|
+
"FROM ep_consumer_registrations WHERE consumer_id=? AND project_id=?",
|
|
193
|
+
(consumer_id, project_id),
|
|
194
|
+
).fetchone()
|
|
195
|
+
finally:
|
|
196
|
+
connection.close()
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def register_consumer(root: Path, *, consumer_id: str, project_id: str) -> dict[str, str | bool | None]:
|
|
200
|
+
consumer_id, project_id = _scope(consumer_id, project_id)
|
|
201
|
+
now = _timestamp(datetime.now(timezone.utc))
|
|
202
|
+
connection = open_storage(root)
|
|
203
|
+
try:
|
|
204
|
+
row = connection.execute(
|
|
205
|
+
"SELECT status,created_at,updated_at,disabled_at,revoked_at FROM ep_consumer_registrations "
|
|
206
|
+
"WHERE consumer_id=? AND project_id=?", (consumer_id, project_id)
|
|
207
|
+
).fetchone()
|
|
208
|
+
if row is None:
|
|
209
|
+
connection.execute(
|
|
210
|
+
"INSERT INTO ep_consumer_registrations(consumer_id,project_id,status,created_at,updated_at,audit_metadata) "
|
|
211
|
+
"VALUES(?,?, 'ACTIVE',?,?,?)", (consumer_id, project_id, now, now, json.dumps({"action":"REGISTER"}, sort_keys=True))
|
|
212
|
+
)
|
|
213
|
+
return {"consumer_id":consumer_id,"project_id":project_id,"status":"ACTIVE","created_at":now,"updated_at":now,"idempotent":False}
|
|
214
|
+
if row[0] != "ACTIVE":
|
|
215
|
+
raise ValueError("consumer registration is not active.")
|
|
216
|
+
return {"consumer_id":consumer_id,"project_id":project_id,"status":"ACTIVE","created_at":str(row[1]),"updated_at":str(row[2]),"idempotent":True}
|
|
217
|
+
finally:
|
|
218
|
+
connection.close()
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def consumer_status(root: Path, *, consumer_id: str, project_id: str) -> dict[str, object]:
|
|
222
|
+
consumer_id, project_id = _scope(consumer_id, project_id)
|
|
223
|
+
row = _registration(root, consumer_id, project_id)
|
|
224
|
+
if row is None:
|
|
225
|
+
raise ValueError("consumer registration is absent.")
|
|
226
|
+
connection = open_storage(root)
|
|
227
|
+
try:
|
|
228
|
+
count = connection.execute(
|
|
229
|
+
"SELECT count(*) FROM ep_consumer_credentials WHERE consumer_id=? AND project_id=? AND credential_id LIKE ? "
|
|
230
|
+
"AND revoked_at IS NULL AND (expires_at IS NULL OR expires_at>CURRENT_TIMESTAMP)",
|
|
231
|
+
(consumer_id, project_id, f"{PRODUCTION_PREFIX}%"),
|
|
232
|
+
).fetchone()[0]
|
|
233
|
+
finally:
|
|
234
|
+
connection.close()
|
|
235
|
+
return {"consumer_id":row[0],"project_id":row[1],"status":row[2],"created_at":row[3],"updated_at":row[4],"disabled_at":row[5],"revoked_at":row[6],"active_production_credentials":count}
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def _set_registration_state(root: Path, *, consumer_id: str, project_id: str, state: str) -> bool:
|
|
239
|
+
consumer_id, project_id = _scope(consumer_id, project_id)
|
|
240
|
+
now = _timestamp(datetime.now(timezone.utc))
|
|
241
|
+
column = "disabled_at" if state == "DISABLED" else "revoked_at"
|
|
242
|
+
connection = open_storage(root)
|
|
243
|
+
try:
|
|
244
|
+
result = connection.execute(
|
|
245
|
+
f"UPDATE ep_consumer_registrations SET status=?,updated_at=?,{column}=?,audit_metadata=? "
|
|
246
|
+
"WHERE consumer_id=? AND project_id=? AND status='ACTIVE'",
|
|
247
|
+
(state, now, now, json.dumps({"action": "DISABLE" if state == "DISABLED" else "REVOKE_REGISTRATION"}, sort_keys=True), consumer_id, project_id),
|
|
248
|
+
)
|
|
249
|
+
existing = connection.execute("SELECT status FROM ep_consumer_registrations WHERE consumer_id=? AND project_id=?", (consumer_id, project_id)).fetchone()
|
|
250
|
+
if existing is None:
|
|
251
|
+
raise ValueError("consumer registration is absent.")
|
|
252
|
+
if existing[0] != state and result.rowcount != 1:
|
|
253
|
+
raise ValueError("consumer registration state conflicts.")
|
|
254
|
+
return result.rowcount == 1
|
|
255
|
+
finally:
|
|
256
|
+
connection.close()
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def disable_consumer(root: Path, *, consumer_id: str, project_id: str) -> bool:
|
|
260
|
+
return _set_registration_state(root, consumer_id=consumer_id, project_id=project_id, state="DISABLED")
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def revoke_consumer(root: Path, *, consumer_id: str, project_id: str) -> bool:
|
|
264
|
+
return _set_registration_state(root, consumer_id=consumer_id, project_id=project_id, state="REVOKED")
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
@dataclass(frozen=True)
|
|
268
|
+
class ProductionCredential:
|
|
269
|
+
credential_id: str
|
|
270
|
+
consumer_id: str
|
|
271
|
+
project_id: str
|
|
272
|
+
fingerprint_hex: str
|
|
273
|
+
created_at: str
|
|
274
|
+
credential: str = field(repr=False)
|
|
275
|
+
|
|
276
|
+
def disclosure(self) -> dict[str, str]:
|
|
277
|
+
return {"credential_id":self.credential_id,"consumer_id":self.consumer_id,"project_id":self.project_id,"purpose":"PRODUCTION_CONSUMER","created_at":self.created_at,"credential":self.credential}
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def issue_credential(root: Path, *, consumer_id: str, project_id: str) -> ProductionCredential:
|
|
281
|
+
consumer_id, project_id = _scope(consumer_id, project_id)
|
|
282
|
+
status = _registration(root, consumer_id, project_id)
|
|
283
|
+
if status is None or status[2] != "ACTIVE":
|
|
284
|
+
raise ValueError("active consumer registration is required.")
|
|
285
|
+
token = secrets.token_urlsafe(32)
|
|
286
|
+
now = _timestamp(datetime.now(timezone.utc))
|
|
287
|
+
credential_id = PRODUCTION_PREFIX + secrets.token_hex(16)
|
|
288
|
+
connection = open_storage(root)
|
|
289
|
+
try:
|
|
290
|
+
count = connection.execute("SELECT count(*) FROM ep_consumer_credentials WHERE consumer_id=? AND project_id=? AND credential_id LIKE ? AND revoked_at IS NULL AND (expires_at IS NULL OR expires_at>CURRENT_TIMESTAMP)", (consumer_id,project_id,f"{PRODUCTION_PREFIX}%")).fetchone()[0]
|
|
291
|
+
if count >= MAX_ACTIVE_PRODUCTION_CREDENTIALS:
|
|
292
|
+
raise ValueError("active production credential limit reached.")
|
|
293
|
+
connection.execute("INSERT INTO ep_consumer_credentials(credential_id,consumer_id,project_id,verifier,fingerprint,issued_at) VALUES(?,?,?,?,?,?)", (credential_id,consumer_id,project_id,verifier(token),fingerprint(token),now))
|
|
294
|
+
finally:
|
|
295
|
+
connection.close()
|
|
296
|
+
return ProductionCredential(credential_id,consumer_id,project_id,fingerprint(token).hex(),now,token)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def credential_status(root: Path, *, consumer_id: str, project_id: str) -> list[dict[str, object]]:
|
|
300
|
+
consumer_id, project_id = _scope(consumer_id, project_id)
|
|
301
|
+
connection = open_storage(root)
|
|
302
|
+
try:
|
|
303
|
+
rows = connection.execute("SELECT credential_id,fingerprint,issued_at,expires_at,revoked_at FROM ep_consumer_credentials WHERE consumer_id=? AND project_id=? AND credential_id LIKE ? ORDER BY issued_at DESC", (consumer_id,project_id,f"{PRODUCTION_PREFIX}%")).fetchall()
|
|
304
|
+
finally:
|
|
305
|
+
connection.close()
|
|
306
|
+
now = _timestamp(datetime.now(timezone.utc))
|
|
307
|
+
return [{"credential_id":str(r[0]),"fingerprint":bytes(r[1]).hex(),"purpose":"PRODUCTION_CONSUMER","created_at":str(r[2]),"expires_at":r[3],"revoked_at":r[4],"active":r[4] is None and (r[3] is None or str(r[3]) > now)} for r in rows]
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def revoke_credential(root: Path, credential_id: str) -> bool:
|
|
311
|
+
if not credential_id.startswith(PRODUCTION_PREFIX):
|
|
312
|
+
raise ValueError("credential_id is not a production credential.")
|
|
313
|
+
connection = open_storage(root)
|
|
314
|
+
try:
|
|
315
|
+
result = connection.execute("UPDATE ep_consumer_credentials SET revoked_at=? WHERE credential_id=? AND revoked_at IS NULL", (_timestamp(datetime.now(timezone.utc)),credential_id))
|
|
316
|
+
if result.rowcount == 0 and connection.execute(
|
|
317
|
+
"SELECT 1 FROM ep_consumer_credentials WHERE credential_id=?", (credential_id,)
|
|
318
|
+
).fetchone() is None:
|
|
319
|
+
raise ValueError("production credential is absent.")
|
|
320
|
+
return result.rowcount == 1
|
|
321
|
+
finally:
|
|
322
|
+
connection.close()
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def rotate_credential(
|
|
326
|
+
root: Path, *, consumer_id: str, project_id: str, old_credential_id: str,
|
|
327
|
+
store: object, authenticate: Callable[[str], bool],
|
|
328
|
+
) -> ProductionCredential:
|
|
329
|
+
"""Issue, securely store and prove a replacement before revoking the old token."""
|
|
330
|
+
replacement = issue_credential(root, consumer_id=consumer_id, project_id=project_id)
|
|
331
|
+
try:
|
|
332
|
+
store.put_credential(consumer_id, project_id, replacement.credential)
|
|
333
|
+
if not authenticate(replacement.credential):
|
|
334
|
+
raise ValueError("replacement credential did not authenticate.")
|
|
335
|
+
except Exception:
|
|
336
|
+
revoke_credential(root, replacement.credential_id)
|
|
337
|
+
raise
|
|
338
|
+
revoke_credential(root, old_credential_id)
|
|
339
|
+
return replacement
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
class CredentialAuthority:
|
|
343
|
+
"""Read-only production authority with explicit in-memory test fixtures."""
|
|
344
|
+
|
|
345
|
+
def __init__(self, root: Path | None = None, record: CredentialScope | None = None) -> None:
|
|
346
|
+
self.root, self.record = root, record
|
|
347
|
+
|
|
348
|
+
@classmethod
|
|
349
|
+
def test_fixture(
|
|
350
|
+
cls, credential: str, *, consumer_id: str, project_id: str
|
|
351
|
+
) -> "CredentialAuthority":
|
|
352
|
+
return cls(record=CredentialScope(consumer_id, project_id, verifier(credential)))
|
|
353
|
+
|
|
354
|
+
def ready(self) -> bool:
|
|
355
|
+
if self.root is None:
|
|
356
|
+
return True
|
|
357
|
+
try:
|
|
358
|
+
connection = open_storage(self.root)
|
|
359
|
+
try:
|
|
360
|
+
connection.execute("SELECT 1 FROM ep_consumer_credentials LIMIT 1").fetchone()
|
|
361
|
+
connection.execute("SELECT 1 FROM ep_consumer_registrations LIMIT 1").fetchone()
|
|
362
|
+
finally:
|
|
363
|
+
connection.close()
|
|
364
|
+
return True
|
|
365
|
+
except Exception:
|
|
366
|
+
return False
|
|
367
|
+
|
|
368
|
+
def authenticate(self, credential: str) -> CredentialScope | None:
|
|
369
|
+
try:
|
|
370
|
+
candidate = verifier(credential)
|
|
371
|
+
except UnicodeEncodeError:
|
|
372
|
+
return None
|
|
373
|
+
if self.record is not None:
|
|
374
|
+
return (
|
|
375
|
+
self.record if hmac.compare_digest(self.record.verifier_value, candidate) else None
|
|
376
|
+
)
|
|
377
|
+
if self.root is None:
|
|
378
|
+
return None
|
|
379
|
+
try:
|
|
380
|
+
connection = open_storage(self.root)
|
|
381
|
+
try:
|
|
382
|
+
row = connection.execute(
|
|
383
|
+
"SELECT credential_id,consumer_id,project_id,verifier FROM ep_consumer_credentials "
|
|
384
|
+
"WHERE verifier=? AND revoked_at IS NULL AND (expires_at IS NULL OR expires_at>CURRENT_TIMESTAMP)",
|
|
385
|
+
(candidate,),
|
|
386
|
+
).fetchone()
|
|
387
|
+
finally:
|
|
388
|
+
connection.close()
|
|
389
|
+
except Exception:
|
|
390
|
+
return None
|
|
391
|
+
if row is None or not hmac.compare_digest(bytes(row[3]), candidate):
|
|
392
|
+
return None
|
|
393
|
+
return CredentialScope(str(row[1]), str(row[2]), bytes(row[3]))
|
|
394
|
+
|
|
395
|
+
def authorized(self, scope: CredentialScope) -> bool:
|
|
396
|
+
"""Evaluate current registration state after bearer authentication."""
|
|
397
|
+
|
|
398
|
+
if self.root is None or self.record is not None:
|
|
399
|
+
return True
|
|
400
|
+
try:
|
|
401
|
+
connection = open_storage(self.root)
|
|
402
|
+
try:
|
|
403
|
+
row = connection.execute(
|
|
404
|
+
"SELECT credential_id FROM ep_consumer_credentials WHERE verifier=?",
|
|
405
|
+
(scope.verifier_value,),
|
|
406
|
+
).fetchone()
|
|
407
|
+
finally:
|
|
408
|
+
connection.close()
|
|
409
|
+
if row is None or not str(row[0]).startswith(PRODUCTION_PREFIX):
|
|
410
|
+
return True
|
|
411
|
+
registration = _registration(self.root, scope.consumer_id, scope.project_id)
|
|
412
|
+
return registration is not None and registration[2] == "ACTIVE"
|
|
413
|
+
except Exception:
|
|
414
|
+
return False
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
def main(argv: list[str] | None = None) -> int:
|
|
418
|
+
parser = argparse.ArgumentParser(prog="engineering-ep-consumer-credentials")
|
|
419
|
+
parser.add_argument(
|
|
420
|
+
"command",
|
|
421
|
+
choices=(
|
|
422
|
+
"create-qualification-credential",
|
|
423
|
+
"qualification-status",
|
|
424
|
+
"revoke-qualification-credential", "consumer-register", "consumer-status",
|
|
425
|
+
"consumer-disable", "consumer-revoke", "credential-issue", "credential-status", "credential-revoke",
|
|
426
|
+
),
|
|
427
|
+
)
|
|
428
|
+
parser.add_argument("--repo", type=Path, default=Path.cwd())
|
|
429
|
+
parser.add_argument("--consumer-id")
|
|
430
|
+
parser.add_argument("--project-id")
|
|
431
|
+
parser.add_argument("--credential-id")
|
|
432
|
+
args = parser.parse_args(argv)
|
|
433
|
+
root = args.repo.resolve()
|
|
434
|
+
try:
|
|
435
|
+
if args.command == "create-qualification-credential":
|
|
436
|
+
if args.consumer_id is None or args.project_id is None:
|
|
437
|
+
raise ValueError("--consumer-id and --project-id are required.")
|
|
438
|
+
print(
|
|
439
|
+
json.dumps(
|
|
440
|
+
create_qualification_credential(
|
|
441
|
+
root, consumer_id=args.consumer_id, project_id=args.project_id
|
|
442
|
+
).disclosure(),
|
|
443
|
+
sort_keys=True,
|
|
444
|
+
)
|
|
445
|
+
)
|
|
446
|
+
return 0
|
|
447
|
+
if args.command == "qualification-status":
|
|
448
|
+
print(json.dumps(qualification_status(root), sort_keys=True))
|
|
449
|
+
return 0
|
|
450
|
+
if args.command in {"consumer-register", "consumer-status", "consumer-disable", "consumer-revoke", "credential-issue", "credential-status"}:
|
|
451
|
+
if args.consumer_id is None or args.project_id is None:
|
|
452
|
+
raise ValueError("--consumer-id and --project-id are required.")
|
|
453
|
+
actions = {"consumer-register": register_consumer, "consumer-status": consumer_status, "consumer-disable": disable_consumer, "consumer-revoke": revoke_consumer, "credential-issue": issue_credential, "credential-status": credential_status}
|
|
454
|
+
result = actions[args.command](root, consumer_id=args.consumer_id, project_id=args.project_id)
|
|
455
|
+
if isinstance(result, (ProductionCredential, QualificationCredential)):
|
|
456
|
+
result = result.disclosure()
|
|
457
|
+
print(json.dumps(result, sort_keys=True))
|
|
458
|
+
return 0
|
|
459
|
+
if args.credential_id is None:
|
|
460
|
+
raise ValueError("--credential-id is required.")
|
|
461
|
+
if args.command == "credential-revoke":
|
|
462
|
+
changed = revoke_credential(root, args.credential_id)
|
|
463
|
+
else:
|
|
464
|
+
changed = revoke_qualification_credential(root, args.credential_id)
|
|
465
|
+
print(json.dumps({"credential_id": args.credential_id, "revoked": True, "changed": changed}, sort_keys=True))
|
|
466
|
+
return 0
|
|
467
|
+
except ValueError as error:
|
|
468
|
+
print(f"ERROR: {error}")
|
|
469
|
+
return 2
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
if __name__ == "__main__":
|
|
473
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""Invocation-local bounded projections for oversized shell evidence.
|
|
2
|
+
|
|
3
|
+
The Engineering runner never persists raw tool output. Codex executes shell
|
|
4
|
+
tools inside its own provider turn, so the temporary PATH proxy created here is
|
|
5
|
+
the only safe interception point: it preserves exit status, returns small or
|
|
6
|
+
source output unchanged, and makes an explicit raw expansion available only to
|
|
7
|
+
the same invocation via ``ENGINEERING_PLATFORM_EVIDENCE_EXPAND=1``.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
import os
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
import json
|
|
15
|
+
import shutil
|
|
16
|
+
import subprocess # nosec B404
|
|
17
|
+
import sys
|
|
18
|
+
from tempfile import TemporaryDirectory
|
|
19
|
+
from typing import Iterable, Mapping
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# Limits are category-specific because passing logs are repetitive, while a
|
|
23
|
+
# failure needs an assertion, traceback and surrounding context to be useful.
|
|
24
|
+
PASSING_TEST_LIMIT = 768
|
|
25
|
+
FAILED_DIAGNOSTIC_LIMIT = 12_288
|
|
26
|
+
SEARCH_MATCH_LIMIT = 24
|
|
27
|
+
SEARCH_LINE_LIMIT = 240
|
|
28
|
+
GIT_FACT_LIMIT = 2_048
|
|
29
|
+
GITHUB_FACT_LIMIT = 4_096
|
|
30
|
+
PROXIED_TOOLS = ("git", "gh", "rg", "grep", "pytest", "python", "python3", "npm", "npx", "engineering-platform-context-escalate")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass(frozen=True)
|
|
34
|
+
class EvidenceProjection:
|
|
35
|
+
category: str
|
|
36
|
+
text: str
|
|
37
|
+
raw_bytes: int
|
|
38
|
+
projected_bytes: int
|
|
39
|
+
more_evidence_available: bool
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def category_for(command: Iterable[str]) -> str:
|
|
43
|
+
values = tuple(command)
|
|
44
|
+
executable = Path(values[0]).name if values else ""
|
|
45
|
+
normalized = " ".join(values).casefold()
|
|
46
|
+
if executable in {"rg", "grep"}:
|
|
47
|
+
return "search"
|
|
48
|
+
if executable == "git":
|
|
49
|
+
return "git"
|
|
50
|
+
if executable == "gh":
|
|
51
|
+
return "github"
|
|
52
|
+
if executable in {"pytest", "npm", "npx"} or (
|
|
53
|
+
executable in {"python", "python3"} and "unittest" in normalized
|
|
54
|
+
):
|
|
55
|
+
return "test"
|
|
56
|
+
return "other"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _bytes(value: str) -> int:
|
|
60
|
+
return len(value.encode("utf-8"))
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _bounded_lines(value: str, *, count: int, width: int) -> str:
|
|
64
|
+
return "\n".join(line[:width] for line in value.splitlines()[:count])
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _failure_tail(value: str) -> str:
|
|
68
|
+
lines = value.splitlines()
|
|
69
|
+
if _bytes(value) <= FAILED_DIAGNOSTIC_LIMIT:
|
|
70
|
+
return value
|
|
71
|
+
head = "\n".join(lines[:30])
|
|
72
|
+
tail = "\n".join(lines[-90:])
|
|
73
|
+
return f"{head}\n… FAILED_DIAGNOSTIC_MIDDLE_OMITTED …\n{tail}"[-FAILED_DIAGNOSTIC_LIMIT:]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def project_output(command: Iterable[str], output: str, exit_code: int) -> EvidenceProjection:
|
|
77
|
+
"""Project one completed command without losing the raw expansion path."""
|
|
78
|
+
category = category_for(command)
|
|
79
|
+
raw_bytes = _bytes(output)
|
|
80
|
+
if not output or category == "other":
|
|
81
|
+
return EvidenceProjection(category, output, raw_bytes, raw_bytes, False)
|
|
82
|
+
if category == "test":
|
|
83
|
+
if exit_code:
|
|
84
|
+
text = _failure_tail(output)
|
|
85
|
+
more = text != output
|
|
86
|
+
if more:
|
|
87
|
+
marker = "\nMORE_EVIDENCE_AVAILABLE: set ENGINEERING_PLATFORM_EVIDENCE_EXPAND=1 for this command."
|
|
88
|
+
text = f"{text[:FAILED_DIAGNOSTIC_LIMIT - _bytes(marker)]}{marker}"
|
|
89
|
+
elif raw_bytes > PASSING_TEST_LIMIT:
|
|
90
|
+
passed = next((line for line in output.splitlines() if "passed" in line.casefold()), "PASS")
|
|
91
|
+
text = f"PASSING_TEST_OUTPUT_BOUNDED\n{passed[:PASSING_TEST_LIMIT // 2]}\nMORE_EVIDENCE_AVAILABLE: set ENGINEERING_PLATFORM_EVIDENCE_EXPAND=1 for this command."
|
|
92
|
+
more = True
|
|
93
|
+
else:
|
|
94
|
+
text, more = output, False
|
|
95
|
+
elif category == "search" and len(output.splitlines()) > SEARCH_MATCH_LIMIT:
|
|
96
|
+
text = _bounded_lines(output, count=SEARCH_MATCH_LIMIT, width=SEARCH_LINE_LIMIT)
|
|
97
|
+
text += f"\nMATCHES_BOUNDED: shown={SEARCH_MATCH_LIMIT} total={len(output.splitlines())}\nMORE_EVIDENCE_AVAILABLE: set ENGINEERING_PLATFORM_EVIDENCE_EXPAND=1 for this command."
|
|
98
|
+
more = True
|
|
99
|
+
elif category == "git" and raw_bytes > GIT_FACT_LIMIT:
|
|
100
|
+
text = _bounded_lines(output, count=32, width=SEARCH_LINE_LIMIT)
|
|
101
|
+
text += "\nGIT_EVIDENCE_BOUNDED\nMORE_EVIDENCE_AVAILABLE: set ENGINEERING_PLATFORM_EVIDENCE_EXPAND=1 for this command."
|
|
102
|
+
more = True
|
|
103
|
+
elif category == "github" and raw_bytes > GITHUB_FACT_LIMIT:
|
|
104
|
+
text = _bounded_lines(output, count=48, width=SEARCH_LINE_LIMIT)
|
|
105
|
+
text += "\nGITHUB_EVIDENCE_BOUNDED\nMORE_EVIDENCE_AVAILABLE: set ENGINEERING_PLATFORM_EVIDENCE_EXPAND=1 for this command."
|
|
106
|
+
more = True
|
|
107
|
+
else:
|
|
108
|
+
text, more = output, False
|
|
109
|
+
return EvidenceProjection(category, text, raw_bytes, _bytes(text), more)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class ToolProxyEnvironment:
|
|
113
|
+
"""Temporary PATH proxy. It retains no output after the invocation ends."""
|
|
114
|
+
|
|
115
|
+
def __init__(self) -> None:
|
|
116
|
+
self._temporary: TemporaryDirectory[str] | None = None
|
|
117
|
+
|
|
118
|
+
def __enter__(self) -> Mapping[str, str]:
|
|
119
|
+
self._temporary = TemporaryDirectory(prefix="engineering-platform-evidence-")
|
|
120
|
+
directory = Path(self._temporary.name)
|
|
121
|
+
repository_root = Path(__file__).resolve().parents[2]
|
|
122
|
+
for name in PROXIED_TOOLS:
|
|
123
|
+
launcher = directory / name
|
|
124
|
+
target = "context_escalation_main" if name == "engineering-platform-context-escalate" else "proxy_main"
|
|
125
|
+
launcher.write_text(
|
|
126
|
+
f"#!{sys.executable}\nimport sys\nsys.path.insert(0, {str(repository_root)!r})\nfrom engineering_platform.evidence_projection import {target}\n{target}({name!r})\n",
|
|
127
|
+
encoding="utf-8",
|
|
128
|
+
)
|
|
129
|
+
launcher.chmod(0o700)
|
|
130
|
+
environment = dict(os.environ)
|
|
131
|
+
environment["ENGINEERING_PLATFORM_EVIDENCE_ORIGINAL_PATH"] = environment.get("PATH", os.defpath)
|
|
132
|
+
environment["PATH"] = f"{directory}{os.pathsep}{environment['ENGINEERING_PLATFORM_EVIDENCE_ORIGINAL_PATH']}"
|
|
133
|
+
environment["ENGINEERING_PLATFORM_CONTEXT_ESCALATION_FILE"] = str(directory / "context-escalations.jsonl")
|
|
134
|
+
return environment
|
|
135
|
+
|
|
136
|
+
def __exit__(self, *_: object) -> None:
|
|
137
|
+
if self._temporary is not None:
|
|
138
|
+
self._temporary.cleanup()
|
|
139
|
+
self._temporary = None
|
|
140
|
+
|
|
141
|
+
def context_escalations(self) -> tuple[dict[str, object], ...]:
|
|
142
|
+
if self._temporary is None:
|
|
143
|
+
return ()
|
|
144
|
+
path = Path(self._temporary.name) / "context-escalations.jsonl"
|
|
145
|
+
try:
|
|
146
|
+
return tuple(
|
|
147
|
+
item for line in path.read_text(encoding="utf-8").splitlines()
|
|
148
|
+
if isinstance((item := json.loads(line)), dict)
|
|
149
|
+
)
|
|
150
|
+
except (OSError, json.JSONDecodeError):
|
|
151
|
+
return ()
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def proxy_main(name: str | None = None) -> None:
|
|
155
|
+
"""Run the proxied command and emit only its bounded invocation-local view."""
|
|
156
|
+
name = name or Path(sys.argv[0]).name
|
|
157
|
+
original_path = os.environ.get("ENGINEERING_PLATFORM_EVIDENCE_ORIGINAL_PATH", os.defpath)
|
|
158
|
+
executable = shutil.which(name, path=original_path)
|
|
159
|
+
if executable is None:
|
|
160
|
+
raise SystemExit(f"Evidence proxy could not resolve {name}.")
|
|
161
|
+
completed = subprocess.run( # nosec B603
|
|
162
|
+
(executable, *sys.argv[1:]), text=True, capture_output=True,
|
|
163
|
+
env={**os.environ, "PATH": original_path}, check=False,
|
|
164
|
+
)
|
|
165
|
+
raw = f"{completed.stdout}{completed.stderr}"
|
|
166
|
+
if os.environ.get("ENGINEERING_PLATFORM_EVIDENCE_EXPAND") == "1":
|
|
167
|
+
sys.stdout.write(raw)
|
|
168
|
+
else:
|
|
169
|
+
sys.stdout.write(project_output((name, *sys.argv[1:]), raw, completed.returncode).text)
|
|
170
|
+
raise SystemExit(completed.returncode)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def context_escalation_main(_: str | None = None) -> None:
|
|
174
|
+
"""Validate and record one bounded historical-context escalation."""
|
|
175
|
+
from .provider_context_scope import ContextEscalationReason, ContextEscalationRequest, HistoryBoundaryKind
|
|
176
|
+
|
|
177
|
+
arguments = sys.argv[1:]
|
|
178
|
+
try:
|
|
179
|
+
diagnostic_index = arguments.index("--diagnostic")
|
|
180
|
+
values, diagnostic = arguments[:diagnostic_index], " ".join(arguments[diagnostic_index + 1:])
|
|
181
|
+
if len(values) != 4:
|
|
182
|
+
raise ValueError("Expected REASON BOUNDARY_KIND BOUNDARY LIMIT.")
|
|
183
|
+
request = ContextEscalationRequest(
|
|
184
|
+
ContextEscalationReason(values[0]), HistoryBoundaryKind(values[1]), values[2], int(values[3]), diagnostic
|
|
185
|
+
).validate()
|
|
186
|
+
except (ValueError, IndexError) as error:
|
|
187
|
+
sys.stderr.write(f"Context escalation rejected: {error}\n")
|
|
188
|
+
raise SystemExit(2)
|
|
189
|
+
path = os.environ.get("ENGINEERING_PLATFORM_CONTEXT_ESCALATION_FILE")
|
|
190
|
+
if not path:
|
|
191
|
+
sys.stderr.write("Context escalation is available only inside an Engineering Platform provider invocation.\n")
|
|
192
|
+
raise SystemExit(2)
|
|
193
|
+
record = {
|
|
194
|
+
"reason": request.reason.value, "boundary_kind": request.boundary_kind.value,
|
|
195
|
+
"boundary": request.boundary, "limit": request.limit, "diagnostic": request.diagnostic,
|
|
196
|
+
}
|
|
197
|
+
with open(path, "a", encoding="utf-8") as handle:
|
|
198
|
+
handle.write(json.dumps(record, sort_keys=True, separators=(",", ":")) + "\n")
|
|
199
|
+
sys.stdout.write("CONTEXT_ESCALATION_ADMITTED\n")
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def deterministic_fixture() -> dict[str, object]:
|
|
203
|
+
"""Comparable raw/projection fixture; it contains no provider or user data."""
|
|
204
|
+
cases = (
|
|
205
|
+
(("rg", "needle"), "\n".join(f"match {item}" for item in range(120)), 0),
|
|
206
|
+
(("git", "log", "--oneline"), "\n".join(f"{item:040x} commit" for item in range(90)), 0),
|
|
207
|
+
(("pytest",), "\n".join(". passing" for _ in range(500)) + "\n500 passed", 0),
|
|
208
|
+
(("pytest",), "FAILED test_example\nAssertionError: expected x\n" + "trace\n" * 400, 1),
|
|
209
|
+
)
|
|
210
|
+
projected = tuple(project_output(command, output, code) for command, output, code in cases)
|
|
211
|
+
raw = sum(item.raw_bytes for item in projected)
|
|
212
|
+
bounded = sum(item.projected_bytes for item in projected)
|
|
213
|
+
return {"raw_tool_output_bytes": raw, "projected_tool_output_bytes": bounded, "suppressed_tool_output_bytes": raw - bounded, "reduction": 0 if not raw else (raw - bounded) / raw, "required_evidence_retained": True, "more_evidence_available": any(item.more_evidence_available for item in projected)}
|