114 lines
5.2 KiB
Python
114 lines
5.2 KiB
Python
"""#215(feat-arch-converge)接口对齐层,CHV 本地实现。
|
||
|
||
背景:#215 未合并,本基线里没有 cloud/timeouts.py、
|
||
cloud/gates.py、cloud/quota.py、cloud/sandbox_policy.py。
|
||
本模块绝不复制 #215 的文件,只把 CHV 真正能映射的
|
||
接口写成与 #215 相同的签名,#215 合并后替换为 import
|
||
即是机械的(见 docs/chv-architecture.md ADR-8)。
|
||
|
||
映射表(逐个核对过 #215 远程分支的真实函数,不是凭空编的):
|
||
- gates.resolve_inside(base, rel):目录门,CHV 快照/磁盘
|
||
路径白名单正好需要它——本模块实现同语义并已在
|
||
hardening.validate_snapshot_url 里使用,#215 合并后
|
||
改为 from cloud.gates import resolve_inside 即可。
|
||
- sandbox_policy.tmpfs_isolated(executor_kind, path):CHV
|
||
客机 /tmp 落在客机磁盘上,不是宿主 tmpfs,故对
|
||
cloud-hypervisor 一律返回 (False, ...)——fail-closed,
|
||
绝不宣称隔离。未知执行器同样 fail-closed。
|
||
- timeouts.resolve_module_timeout / quota.decide:无映射。
|
||
前者是审批/队列超时(None=不过期、0=不过期),CHV
|
||
的 api/ready 超时是秒数且 0 无效,语义不同,硬套会
|
||
改行为;后者是按月美元配额,CHV 的配额是 VM 数/磁盘
|
||
GB/快照数,单位不同。两者在本模块里 deliberately
|
||
不提供,测试钉住“CHV 不 import 它们”。
|
||
|
||
本模块只依赖标准库,是叶子模块,不 import cloud.sandbox。
|
||
|
||
合并后替换清单(REPLACEMENT_POINTS,本轨从“接口形状”
|
||
推进到可机械执行的清单;#215 未合并前一律不 import
|
||
cloud.gates / cloud.sandbox_policy / cloud.timeouts /
|
||
cloud.quota,测试钉住这些模块在本基线里不存在):
|
||
- R1 gates.resolve_inside:唯一生产调用方是
|
||
hardening._is_within(快照 URL 白名单)。合并后两步:
|
||
① hardening 改为 `from cloud.gates import resolve_inside`;
|
||
② 删本模块 resolve_inside。语义必须逐字一致,改完
|
||
重跑快照白名单测试(逃逸/符号链接/绝对路径三例)。
|
||
- R2 sandbox_policy.tmpfs_isolated:形状占位,当前无
|
||
生产调用方(只有测试)。合并后一步:删本模块
|
||
tmpfs_isolated;将来有调用方时直接 import #215 版,
|
||
不得再本地复刻。CHV 语义是“一律不隔离(fail-closed)”,
|
||
若 #215 版对 cloud-hypervisor 返回 True,替换即改行为,
|
||
必须先停下来核对,不得机械替换。
|
||
- R3 timeouts / quota:永不替换。#215 的 timeouts 是
|
||
审批/队列超时(None/0 = 不过期),quota 是按月美元
|
||
配额;CHV 的 api/ready 超时是秒数(0 无效)、配额是
|
||
VM 数/磁盘 GB/快照数,单位与语义都不同。清单里明写
|
||
“不替换”,防止合并时有人按名字硬套。
|
||
"""
|
||
|
||
import os
|
||
|
||
# 合并后替换清单:每项的 local/replacement/test 字段由测试
|
||
# 逐项核对(local 函数真实存在、#215 模块当前不存在、
|
||
# test 命名的测试类真实存在),清单本身不得漂移。
|
||
REPLACEMENT_POINTS = (
|
||
{
|
||
"id": "R1",
|
||
"upstream": "cloud.gates.resolve_inside",
|
||
"local": "cloud.chv.compat215.resolve_inside",
|
||
"caller": "cloud.chv.hardening._is_within",
|
||
"replacement": "hardening 改为 from cloud.gates import "
|
||
"resolve_inside,并删除本地 resolve_inside",
|
||
"test": "Compat215Test + 快照白名单测试",
|
||
},
|
||
{
|
||
"id": "R2",
|
||
"upstream": "cloud.sandbox_policy.tmpfs_isolated",
|
||
"local": "cloud.chv.compat215.tmpfs_isolated",
|
||
"caller": None,
|
||
"replacement": "删除本地 tmpfs_isolated;有调用方时"
|
||
"直接 import #215 版(先核对 CHV 一律 False 语义)",
|
||
"test": "Compat215Test.test_tmpfs_isolated_chv_and_unknown_"
|
||
"fail_closed",
|
||
},
|
||
{
|
||
"id": "R3",
|
||
"upstream": "cloud.timeouts / cloud.quota",
|
||
"local": None,
|
||
"caller": None,
|
||
"replacement": None,
|
||
"test": "Compat215Test.test_no_timeout_or_quota_map",
|
||
},
|
||
)
|
||
|
||
|
||
def resolve_inside(base: str, rel: str) -> str | None:
|
||
"""目录门:base 内的相对路径安全解析,越界回 None。
|
||
|
||
空串回 base 本身;绝对路径、.. 逃逸、符号链接逃逸、
|
||
commonpath 跨盘符 ValueError 一律 None。签名与 #215
|
||
的 gates.resolve_inside 一致,合并后可直接替换为 import。"""
|
||
if not rel:
|
||
return base
|
||
if os.path.isabs(rel):
|
||
return None
|
||
real_base = os.path.realpath(base)
|
||
target = os.path.realpath(os.path.join(real_base, rel))
|
||
try:
|
||
if os.path.commonpath([real_base, target]) != real_base:
|
||
return None
|
||
except ValueError:
|
||
return None
|
||
return target
|
||
|
||
|
||
def tmpfs_isolated(executor_kind: str, path: str) -> tuple[bool, str]:
|
||
"""某执行器下某路径是否走 tmpfs 隔离:(isolated, reason)。
|
||
|
||
cloud-hypervisor:客机 /tmp 落在客机磁盘上,不走宿主
|
||
tmpfs,一律 (False, ...);未知执行器 fail-closed 同样
|
||
False。签名与 #215 的 sandbox_policy.tmpfs_isolated 一致。"""
|
||
if executor_kind == "cloud-hypervisor":
|
||
return False, "CHV 客机 /tmp 落在客机磁盘上,不走宿主 tmpfs"
|
||
return False, "未知执行器,按不隔离处理(fail-closed 口径)"
|