feat(hardening): build scoped Grant writers per service

This commit is contained in:
Codex
2026-07-21 11:48:11 +08:00
parent 382fe662a3
commit fc8bd8c8d4
@@ -1,11 +1,11 @@
"""AIOS V2 运维操作 Provenance Gate 与生产 Writer 工厂。"""
"""AIOS V2 运维操作 Provenance Gate 与服务级 Scoped Writer 工厂。"""
from __future__ import annotations
import json
import os
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Any, Mapping, Protocol
from typing import Any, Mapping, Protocol, Sequence
from .provenance import (
Ed25519PublicKeyVerifier,
@@ -17,12 +17,8 @@ from .provenance import (
SQLiteProvenanceStore,
digest_payload,
)
from .provenance_grants import (
GrantAuthorization,
GrantVerifier,
LeastPrivilegeProvenanceWriter,
SQLiteGrantStore,
)
from .provenance_grants import GrantAuthorization, GrantVerifier, SQLiteGrantStore
from .provenance_scoped import ScopedLeastPrivilegeProvenanceWriter
class AuthorizationWriter(Protocol):
@@ -67,7 +63,7 @@ class OperationReceipt:
class ProvenanceOperationGate:
"""部署、回滚和审计操作的统一授权入口。"""
"""部署、回滚、审计和运行操作的统一授权入口。"""
def __init__(self, writer: AuthorizationWriter) -> None:
self.writer = writer
@@ -151,33 +147,45 @@ _GRANT_ENV_BY_PATH: Mapping[str, str] = {
}
def grant_ids_from_environment() -> dict[str, str]:
values = {
path: os.getenv(variable, "").strip()
for path, variable in _GRANT_ENV_BY_PATH.items()
}
configured = {path: value for path, value in values.items() if value}
if configured and len(configured) != len(values):
missing = [
variable
for path, variable in _GRANT_ENV_BY_PATH.items()
if not values[path]
]
raise RuntimeError(
f"partial least-privilege Provenance Grant configuration; missing {missing}"
def grant_ids_from_environment(
*,
required_paths: Sequence[str] | None = None,
) -> dict[str, str]:
paths = tuple(
sorted(
{
ExecutionPath(path).value
for path in (required_paths or tuple(item.value for item in ExecutionPath))
}
)
return configured
)
values = {
path: os.getenv(_GRANT_ENV_BY_PATH[path], "").strip()
for path in paths
}
missing = [
_GRANT_ENV_BY_PATH[path]
for path, value in values.items()
if not value
]
if missing:
raise RuntimeError(
f"missing scoped Provenance Grant configuration: {missing}"
)
return values
def build_provenance_writer_from_env(
*,
state_dir: str | Path | None = None,
required: bool | None = None,
required_paths: Sequence[str] | None = None,
writer_id: str = "aios-v2-scoped-grant-writer",
) -> AuthorizationWriter | None:
"""从环境构建验证 Writer。
"""从环境构建服务级最小权限 Writer。
生产强制模式必须配置七个独立子 Grant。旧全权限 Writer 只允许在显式关闭
强制模式的候选/测试环境中使用。
生产强制模式必须显式声明当前进程需要的路径;仅加载这些路径对应的 Grant。
旧全权限 Writer 只允许在显式关闭强制模式的候选/测试环境中使用。
"""
require_value = (
@@ -195,8 +203,6 @@ def build_provenance_writer_from_env(
receipt_root = os.getenv(
"AIOS_PROVENANCE_RECEIPT_DIR", str(base / "provenance-receipts")
).strip()
grant_ids = grant_ids_from_environment()
configured = bool(public_key_file and key_id)
if not configured:
if require_value:
@@ -207,22 +213,33 @@ def build_provenance_writer_from_env(
verifier = Ed25519PublicKeyVerifier.from_file(public_key_file, key_id=key_id)
parent_store = SQLiteProvenanceStore(store_file)
if grant_ids:
normalized_paths = tuple(
sorted(
{
ExecutionPath(path).value
for path in (required_paths or ())
}
)
)
if require_value:
if not normalized_paths:
raise RuntimeError(
"production Run Provenance requires explicit service scope"
)
grant_ids = grant_ids_from_environment(required_paths=normalized_paths)
grant_store = SQLiteGrantStore(store_file)
trusted_grants = GrantVerifier(
parent_store,
grant_store,
{key_id: verifier},
)
return LeastPrivilegeProvenanceWriter(
return ScopedLeastPrivilegeProvenanceWriter(
trusted_grants,
receipt_root,
grant_ids,
)
if require_value:
raise RuntimeError(
"production Run Provenance requires seven independent Grant IDs; full-rights provenance is prohibited"
required_paths=normalized_paths,
writer_id=writer_id,
)
legacy = ProvenanceVerifier(parent_store, {key_id: verifier})