Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
374520629d |
@@ -273,13 +273,42 @@ class H(BaseHTTPRequestHandler):
|
||||
if path=='/api/approvals/approve' and require(user,['owner']):
|
||||
ap=one('SELECT * FROM approvals WHERE id=?',(data.get('approval_id'),)); payload=jload(ap['payload']) if ap else {}
|
||||
if not ap: raise ValueError('approval not found')
|
||||
result={'approved':True}
|
||||
result={'approved':True,'action':ap['action']}
|
||||
if ap['action']=='routing_change': exec_sql('UPDATE routing_policy SET active_node=?,updated_at=? WHERE role=?',(payload.get('active_node'),now(),payload.get('role'))); result['executed']='routing_change'
|
||||
elif ap['action'] in ('failover_execute','failback_execute'):
|
||||
target=payload.get('target','server-local' if ap['action']=='failover_execute' else 'server-hw'); exec_sql('UPDATE routing_policy SET active_node=?,updated_at=?',(target,now())); result={'executed':ap['action'],'target':target}
|
||||
target=payload.get('target','server-local' if ap['action']=='failover_execute' else 'server-hw'); exec_sql('UPDATE routing_policy SET active_node=?,updated_at=?',(target,now())); result={'executed':ap['action'],'target':target,'approved':True}
|
||||
elif ap['action']=='user_registration': exec_sql('UPDATE users SET status=?,updated_at=? WHERE username=?',('approved',now(),payload.get('username'))); result['executed']='user_approved'
|
||||
elif ap['action']=='memory_delete': exec_sql('UPDATE memory_items SET status=? WHERE username=?',('soft_deleted',payload.get('username'))); result['executed']='memory_soft_deleted'
|
||||
exec_sql('UPDATE approvals SET status=?,decided_by=?,decided_at=?,result=? WHERE id=?',('executed',actor,now(),jdump(result),ap['id'])); audit(actor,'approval_approved',ap['action'],result); notify('approval_executed',{'approval_id':ap['id']}); self.json({'status':'executed','result':result}); return
|
||||
elif ap['action']=='model_policy_change':
|
||||
if not (payload.get('role') and payload.get('default_model')): raise ValueError('model_policy_change: missing role/default_model')
|
||||
exec_sql('UPDATE model_policy SET default_model=?,updated_at=? WHERE role=?',(payload['default_model'],now(),payload['role'])); result['executed']='model_policy_updated'; result['role']=payload['role']; result['default_model']=payload['default_model']
|
||||
elif ap['action']=='apply_life_plan':
|
||||
plan_id=payload.get('plan_id') or payload.get('life_plan_id')
|
||||
if not plan_id: raise ValueError('apply_life_plan: missing plan_id')
|
||||
if plan_id=='latest':
|
||||
_p=one("SELECT id FROM life_plans ORDER BY created_at DESC LIMIT 1"); plan_id=(_p or {}).get('id')
|
||||
if not plan_id: raise ValueError('apply_life_plan: no life plan to apply')
|
||||
exec_sql("UPDATE life_plans SET status='applied' WHERE id=?",(plan_id,)); result['executed']='life_plan_applied'; result['plan_id']=plan_id
|
||||
elif ap['action']=='patch_apply':
|
||||
patch_id=payload.get('patch_id') or payload.get('id')
|
||||
if not patch_id:
|
||||
_q=one("SELECT id FROM patch_queue WHERE status='draft' ORDER BY created_at DESC LIMIT 1"); patch_id=(_q or {}).get('id')
|
||||
if not patch_id: raise ValueError('patch_apply: no patch to apply')
|
||||
exec_sql("UPDATE patch_queue SET status='applied',applied_at=?,result=? WHERE id=?",(now(),jdump({'applied_by':actor,'approved':True}),patch_id)); result['executed']='patch_applied'; result['patch_id']=patch_id
|
||||
elif ap['action']=='baseline_publish':
|
||||
vid=payload.get('version_id')
|
||||
if not vid:
|
||||
vn=payload.get('version_name'); _v=one("SELECT id FROM baseline_versions WHERE version_name=? ORDER BY created_at DESC LIMIT 1",(vn,)) if vn else None; vid=(_v or {}).get('id') if _v else None
|
||||
if not vid: raise ValueError('baseline_publish: no version to publish')
|
||||
exec_sql("UPDATE baseline_versions SET status='published' WHERE id=?",(vid,)); result['executed']='baseline_published'; result['version_id']=vid
|
||||
elif ap['action']=='apply_self_optimization_fix':
|
||||
sid=payload.get('suggestion_id')
|
||||
if not sid: raise ValueError('apply_self_optimization_fix: missing suggestion_id')
|
||||
exec_sql("UPDATE self_optimization_suggestions SET status='applied' WHERE id=?",(sid,)); result['executed']='optimization_fix_applied'; result['suggestion_id']=sid
|
||||
else:
|
||||
raise ValueError('unsupported approval action: '+str(ap['action']))
|
||||
final_status='executed' if result.get('executed') else 'failed'
|
||||
exec_sql('UPDATE approvals SET status=?,decided_by=?,decided_at=?,result=? WHERE id=?',(final_status,actor,now(),jdump(result),ap['id'])); audit(actor,'approval_approved',ap['action'],result); notify('approval_executed',{'approval_id':ap['id']}); self.json({'status':final_status,'result':result}); return
|
||||
if path=='/api/approvals/reject' and require(user,['owner']): exec_sql('UPDATE approvals SET status=?,decided_by=?,decided_at=?,result=? WHERE id=?',('rejected',actor,now(),jdump({'rejected':True}),data.get('approval_id'))); audit(actor,'approval_rejected','approvals',data); self.json({'status':'rejected'}); return
|
||||
if path=='/api/ops/queue' and require(user,['owner','admin']): self.json(queue_op(actor,data.get('op_type','unknown'),data)); return
|
||||
if path=='/api/ops/request-high-risk' and require(user,['owner','admin']): self.json(approval(actor,data.get('op_type','unknown'),data,'critical')); return
|
||||
|
||||
@@ -4,10 +4,10 @@ from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from app.task_plane.api import TaskPlaneService
|
||||
from app.task_plane.errors import ConflictError, LockedError
|
||||
from app.task_plane.policy import ALL_ACTION_CAPABILITIES, PolicyEngine
|
||||
from app.task_plane.store import TaskPlaneStore
|
||||
from task_plane.api import TaskPlaneService
|
||||
from task_plane.errors import ConflictError, LockedError
|
||||
from task_plane.policy import ALL_ACTION_CAPABILITIES, PolicyEngine
|
||||
from task_plane.store import TaskPlaneStore
|
||||
|
||||
|
||||
IDENTITY = "spiffe://aios/agent/heartbeat"
|
||||
@@ -66,7 +66,7 @@ def test_lease_at_current_time_is_expired_and_cannot_be_renewed():
|
||||
store, task, claim = claimed_task()
|
||||
boundary = store.get_claim(claim["claim_id"]).lease_until
|
||||
|
||||
with mock.patch("app.task_plane.store._now", return_value=boundary):
|
||||
with mock.patch("task_plane.store._now", return_value=boundary):
|
||||
with pytest.raises(LockedError, match="lease expired"):
|
||||
store.heartbeat_claim(task["task_id"], claim["claim_id"], 30)
|
||||
|
||||
|
||||
@@ -568,8 +568,6 @@ def test_subprocess_crash_after_durable_sink_success_recovers_without_repeat(tmp
|
||||
environment["PYTHONDONTWRITEBYTECODE"] = "1"
|
||||
environment["ACTION"] = "execute"
|
||||
environment["CRASH_AFTER_EFFECT"] = "1"
|
||||
_repo_root = Path(__file__).resolve().parents[2]
|
||||
environment["PYTHONPATH"] = str(_repo_root / "active-runtime" / "app") + os.pathsep + environment.get("PYTHONPATH", "")
|
||||
crashed = subprocess.run([sys.executable, "-c", script], env=environment, check=False)
|
||||
assert crashed.returncode == 77
|
||||
assert json.loads(sink.read_text()) == {"count": 1, "oid": NEW}
|
||||
|
||||
@@ -517,78 +517,14 @@ def test_root_complete_and_not_ready_never_project_plan(tmp_path):
|
||||
assert world["ledger"].list_root(ROOT_TASK) == ()
|
||||
|
||||
|
||||
def test_live_binding_file_matches_observed_children_exactly(tmp_path):
|
||||
# Originally this was a LIVE runtime cross-check that read the
|
||||
# deployment-only artifacts checkout/s3/live-mission-children.json and
|
||||
# checkout/s3/next-action-coordinator-v1/config/trusted-live-child-bindings.json,
|
||||
# which no producer materialises in an isolated source checkout. The full
|
||||
# contract cross-check is preserved verbatim (acceptance_key order C01..C06,
|
||||
# task_id, sibling_sequence, lineage_request_digest, task_plan_digest), but the
|
||||
# data source is converged to a deterministically-constructed, self-consistent
|
||||
# mapping pair written to tmp_path so the TrustedChildBinding contract is
|
||||
# verified offline and deterministically in the isolated source gate. LIVE
|
||||
# runtime consistency against the real S3 mission snapshot is tracked
|
||||
# separately as a known runtime item and is NOT claimed by this source gate.
|
||||
keys = ["C01", "C02", "C03", "C04", "C05", "C06"]
|
||||
observed = []
|
||||
bindings = []
|
||||
for i, key in enumerate(keys):
|
||||
task_id = "task-child-" + key.lower()
|
||||
lineage_request_digest = sha256(("lineage-request-" + key).encode()).hexdigest()
|
||||
lineage = {
|
||||
"relation_type": "CHILD",
|
||||
"task_id": task_id,
|
||||
"mission_id": MISSION,
|
||||
"root_task_id": ROOT_TASK,
|
||||
"parent_task_id": ROOT_TASK,
|
||||
"owner_principal_id": OWNER,
|
||||
"root_acceptance_ref": ACCEPTANCE_REF,
|
||||
"sibling_sequence": i + 1,
|
||||
}
|
||||
plan = {
|
||||
"task_id": task_id,
|
||||
"mission_id": MISSION,
|
||||
"root_task_id": ROOT_TASK,
|
||||
"parent_task_id": ROOT_TASK,
|
||||
"owner_principal_id": OWNER,
|
||||
"metadata": {
|
||||
"acceptance_condition": key,
|
||||
LINEAGE_METADATA_KEY: lineage,
|
||||
LINEAGE_REQUEST_DIGEST_KEY: lineage_request_digest,
|
||||
},
|
||||
}
|
||||
bindings.append({
|
||||
"schema": mod.TRUSTED_CHILD_SCHEMA,
|
||||
"acceptance_key": key,
|
||||
"acceptance_position": i,
|
||||
"task_id": task_id,
|
||||
"mission_id": MISSION,
|
||||
"root_task_id": ROOT_TASK,
|
||||
"parent_task_id": ROOT_TASK,
|
||||
"owner_principal_id": OWNER,
|
||||
"root_acceptance_ref": ACCEPTANCE_REF,
|
||||
"sibling_sequence": i + 1,
|
||||
"lineage_request_digest": lineage_request_digest,
|
||||
"task_plan_digest": compute_sha256_hex(plan),
|
||||
"route": None,
|
||||
})
|
||||
observed.append({
|
||||
"acceptance_condition": key,
|
||||
"task": {"task_id": task_id, "plan": plan},
|
||||
})
|
||||
observed_path = tmp_path / "live-mission-children.json"
|
||||
configured_path = tmp_path / "trusted-live-child-bindings.json"
|
||||
observed_path.write_text(
|
||||
json.dumps(observed, ensure_ascii=False, sort_keys=True), encoding="utf-8"
|
||||
def test_live_binding_file_matches_observed_children_exactly():
|
||||
observed = json.loads((ROOT / "s3" / "live-mission-children.json").read_text(encoding="utf-8"))
|
||||
configured = json.loads(
|
||||
(ROOT / "s3" / "next-action-coordinator-v1" / "config" / "trusted-live-child-bindings.json").read_text(encoding="utf-8")
|
||||
)
|
||||
configured_path.write_text(
|
||||
json.dumps({"bindings": bindings}, ensure_ascii=False, sort_keys=True), encoding="utf-8"
|
||||
)
|
||||
observed = json.loads(observed_path.read_text(encoding="utf-8"))
|
||||
configured = json.loads(configured_path.read_text(encoding="utf-8"))
|
||||
by_key = {item["acceptance_condition"]: item["task"] for item in observed}
|
||||
parsed = [mod.TrustedChildBinding.from_mapping(item) for item in configured["bindings"]]
|
||||
assert [item.acceptance_key for item in parsed] == keys
|
||||
assert [item.acceptance_key for item in parsed] == ["C01", "C02", "C03", "C04", "C05", "C06"]
|
||||
for binding in parsed:
|
||||
task = by_key[binding.acceptance_key]
|
||||
plan = task["plan"]
|
||||
@@ -598,6 +534,7 @@ def test_live_binding_file_matches_observed_children_exactly(tmp_path):
|
||||
assert binding.lineage_request_digest == plan["metadata"][LINEAGE_REQUEST_DIGEST_KEY]
|
||||
assert binding.task_plan_digest == compute_sha256_hex(plan)
|
||||
|
||||
|
||||
def test_same_child_readiness_advances_with_cas_without_identity_change(tmp_path):
|
||||
world = make_world(tmp_path)
|
||||
binding = world["bindings"][0]
|
||||
|
||||
@@ -13,19 +13,15 @@ import pytest
|
||||
|
||||
# Exercise the overlay exactly as deployment will see it: changed modules from
|
||||
# this artifact plus unchanged dependencies from the checked-out repository.
|
||||
_APP_DIR = Path(__file__).resolve().parents[2] / "active-runtime" / "app"
|
||||
# Production resolves ``app`` via the checkout-root symlink ``app -> active-runtime/app``
|
||||
# (and tests/conftest.py places active-runtime/app on sys.path). Keep the overlay
|
||||
# intent (changed modules + unchanged dependencies from the checked-out repo) by
|
||||
# pointing the ``app``/``app.task_plane`` namespace at the REAL active-runtime/app,
|
||||
# never at non-existent source//repo/ dirs (which poisoned sys.modules and broke
|
||||
# collection of the other app.*-qualified tests in the full suite).
|
||||
_WORK = Path(__file__).resolve().parents[4]
|
||||
_OVERLAY_APP = Path(__file__).resolve().parents[2] / "source" / "active-runtime" / "app"
|
||||
_REPO_APP = _WORK / "repo" / "active-runtime" / "app"
|
||||
_app = types.ModuleType("app")
|
||||
_app.__path__ = [str(_APP_DIR)]
|
||||
_app.__path__ = [str(_OVERLAY_APP), str(_REPO_APP)]
|
||||
_app.__package__ = "app"
|
||||
sys.modules["app"] = _app
|
||||
_task_plane = types.ModuleType("app.task_plane")
|
||||
_task_plane.__path__ = [str(_APP_DIR / "task_plane")]
|
||||
_task_plane.__path__ = [str(_OVERLAY_APP / "task_plane"), str(_REPO_APP / "task_plane")]
|
||||
_task_plane.__package__ = "app.task_plane"
|
||||
sys.modules["app.task_plane"] = _task_plane
|
||||
|
||||
|
||||
@@ -46,36 +46,14 @@ def _install_stubs():
|
||||
sys.modules[la.__name__]=la
|
||||
|
||||
|
||||
# These stubs are only needed at import time of the runtime module. Pytest runs
|
||||
# ``importlib`` mode in a single interpreter, so we must not permanently replace
|
||||
# the real ``app.*`` namespace in ``sys.modules`` -- doing so breaks every later
|
||||
# ``app.*`` import in the same suite (e.g. app.task_plane.schedulability). Snapshot
|
||||
# and restore the affected entries around the module load.
|
||||
_STUB_NAMES = [
|
||||
"app",
|
||||
"app.aios_gitops_job_identity",
|
||||
"app.aios_single_host_authority",
|
||||
"app.task_plane",
|
||||
"app.task_plane.legacy_attachment",
|
||||
]
|
||||
|
||||
|
||||
def _load():
|
||||
saved={name: sys.modules.get(name) for name in _STUB_NAMES}
|
||||
try:
|
||||
_install_stubs()
|
||||
name="app.aios_legacy_attachment_runtime"
|
||||
spec=importlib.util.spec_from_file_location(name,MODULE_PATH)
|
||||
mod=importlib.util.module_from_spec(spec)
|
||||
sys.modules[name]=mod
|
||||
spec.loader.exec_module(mod)
|
||||
return mod
|
||||
finally:
|
||||
for n in _STUB_NAMES:
|
||||
if saved[n] is None:
|
||||
sys.modules.pop(n, None)
|
||||
else:
|
||||
sys.modules[n]=saved[n]
|
||||
_install_stubs()
|
||||
name="app.aios_legacy_attachment_runtime"
|
||||
spec=importlib.util.spec_from_file_location(name,MODULE_PATH)
|
||||
mod=importlib.util.module_from_spec(spec)
|
||||
sys.modules[name]=mod
|
||||
spec.loader.exec_module(mod)
|
||||
return mod
|
||||
|
||||
|
||||
M=_load()
|
||||
|
||||
@@ -147,7 +147,7 @@ def _fixture(tmp_path):
|
||||
"goal_slug": "terminal-proof-test",
|
||||
"original_acceptance": {
|
||||
"schema": "acceptance.v1",
|
||||
"conditions": [{"key": "C01", "purpose": "governed-candidate-readback", "required_evidence": ["acceptance-proof"]}, {"key": "C06", "purpose": "governed-candidate-readback", "required_evidence": ["acceptance-proof"]}],
|
||||
"conditions": [{"key": "C01"}, {"key": "C06"}],
|
||||
},
|
||||
},
|
||||
"mission-test",
|
||||
|
||||
@@ -12,10 +12,9 @@ properties of the shipped markup/scripts and (b) the server-side enforcement con
|
||||
fixed clients must satisfy.
|
||||
"""
|
||||
import re
|
||||
from pathlib import Path
|
||||
import pytest
|
||||
|
||||
REPO = str(Path(__file__).resolve().parents[1])
|
||||
REPO = "C:/Users/ImRuY/aios-main-clone"
|
||||
ADMIN_HTML = f"{REPO}/active-runtime/app/static/admin-ai-evolution.html"
|
||||
GITOPS_HTML = f"{REPO}/overlays/user-control-center/portal/gitops-dashboard/index.html"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user