Skip to content

Commit c532fb9

Browse files
committed
fix(reliability): guard offline retention namespace symlinks
Signed-off-by: catwithtudou <42607255+catwithtudou@users.noreply.github.com>
1 parent 40baeb9 commit c532fb9

2 files changed

Lines changed: 13 additions & 3 deletions

File tree

‎examples/reliability_diagnostics/ledger-retention-smoke.py‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def shell_env(base: Path, runtime: Path, provider: Path, goal: str = FIXTURE_GOA
9999

100100
with tempfile.TemporaryDirectory(prefix="loopx-retention-smoke-") as tmp:
101101
root = Path(tmp)
102-
cases = ("degraded", "invalid", "symlink", "foreign", "mixed", "malformed",
102+
cases = ("degraded", "invalid", "symlink", "namespace-symlink", "foreign", "mixed", "malformed",
103103
"collision", "copy-tamper", "source-tamper", "restore-tamper", "occupied")
104104
for case in cases:
105105
base = root / case
@@ -139,6 +139,10 @@ def shell_env(base: Path, runtime: Path, provider: Path, goal: str = FIXTURE_GOA
139139
if case == "symlink":
140140
ledger.rename(backing)
141141
ledger.symlink_to(backing)
142+
elif case == "namespace-symlink":
143+
backing = base / "outside-ledgers"
144+
ledger.parent.rename(backing)
145+
ledger.parent.symlink_to(backing, target_is_directory=True)
142146
sentinel = runtime / "authority-sibling.json"
143147
sentinel.write_bytes(b'{"synthetic":"unchanged"}\n')
144148
case_env = shell_env(base, runtime, runtime / "reliability_diagnostics", goal)
@@ -181,6 +185,10 @@ def shell_env(base: Path, runtime: Path, provider: Path, goal: str = FIXTURE_GOA
181185
if case == "symlink":
182186
assert ledger.is_symlink() and backing.read_bytes() == content
183187
assert not any(p.exists() for p in exports)
188+
elif case == "namespace-symlink":
189+
assert "symlink ledger namespace" in result.stderr
190+
assert (backing / ledger.name).read_bytes() == content
191+
assert ledger.parent.is_symlink() and not archives
184192
elif case in {"foreign", "mixed", "malformed", "collision"}:
185193
assert ledger.read_bytes() == content and not any(p.exists() for p in exports)
186194
elif case == "source-tamper":

‎loopx/capabilities/reliability_diagnostics/docs/local-retention-v0.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ if provider.resolve() != expected.resolve():
100100
raise SystemExit("unsupported provider ledger directory: canonical runtime layout required")
101101
if provider.is_symlink():
102102
raise SystemExit("symlink ledger directory: hold offline operations")
103+
if (provider / "by-goal").is_symlink():
104+
raise SystemExit("symlink ledger namespace: hold offline operations")
103105
PY
104106
umask 077
105107
diagnostic_archive=$(mktemp -d "${TMPDIR:-/tmp}/loopx-diagnostics.XXXXXX")
@@ -187,7 +189,7 @@ python examples/reliability_diagnostics/ledger-retention-smoke.py --installed
187189
The smoke executes this literal shell block with the selected interpreter's
188190
real CLI against disposable state. It restores degraded and refused-control
189191
input ledgers with identical bytes and receipt/projection, including invalid
190-
missing-ledger readback after deletion. Symlinks, foreign/mixed ownership,
192+
missing-ledger readback after deletion. Provider, namespace and file symlinks, foreign/mixed ownership,
191193
malformed input and legacy filename collisions stop before ledger export;
192194
source/copy tampering and occupied restore destinations are rejected. Synthetic
193195
sibling state stays unchanged. The existing DSH producer's real resolver and
@@ -260,7 +262,7 @@ public-safe 聚合。保留全部失败标记,不筛选“成功”行。
260262
冻结 provider 配置中记录的真实目录填入 `diagnostic_provider_ledger_dir`,记录同一安装版本。
261263
本 v0 只支持 canonical 布局:该目录须与 `<runtime-root>/reliability_diagnostics` 对应。
262264
任意 custom directory 的 parent 无法建立映射,因为 CLI 会固定添加 `reliability_diagnostics`;
263-
preflight 会在 CLI 读回和导出前拒绝不匹配或 symlink directory。保留原件供另行授权的恢复
265+
preflight 会在 CLI 读回和导出前拒绝不匹配、provider 或 `by-goal` symlink directory。保留原件供另行授权的恢复
264266
路径使用,不要移动、重新 ingest 或删除文件来绕过此 hold,也不能依赖当前 shell 的 env、
265267
当前项目或默认路径猜测实际目录。
266268
3. 新文件使用精确 Goal id 的 UTF-8 SHA-256 小写摘要,放在独立的 `by-goal` 子目录;

0 commit comments

Comments
 (0)