P04-01: 同時発生の更新規約
This commit is contained in:
+41
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"py_compile_ast": [
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/s5/run_s5_native.py",
|
||||
"sha256": "e96b2793d7352ac52e16505c9c4cde3d151497763be3cb47926338df070b05e5",
|
||||
"py_compile": "passed",
|
||||
"ast": "passed",
|
||||
"top_level_functions": [
|
||||
"r17_relocation_guard",
|
||||
"probe_guard",
|
||||
"module",
|
||||
"pin",
|
||||
"load_uid_helper",
|
||||
"make_uid_policy",
|
||||
"engine_pin",
|
||||
"select_mode",
|
||||
"fresh_q_guard",
|
||||
"main"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/s5/s5_uid_controls.py",
|
||||
"sha256": "17069b87b98c385e1298152c9c5c2f23c8710b79eb19aef073c64ce215f6c902",
|
||||
"py_compile": "passed",
|
||||
"ast": "passed",
|
||||
"top_level_functions": [
|
||||
"module",
|
||||
"main"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "docs/plans/original-completion-2026-10-02/execution/p04-01/s5/s5_wrapper_fixtures.py",
|
||||
"sha256": "1a4daebf46051e975a9cc740660c4672371ea6a9e6cb04cbc1d458ece5f0151d",
|
||||
"py_compile": "passed",
|
||||
"ast": "passed",
|
||||
"top_level_functions": [
|
||||
"main"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
# REPAIR36 — bounded preparation submitted, no acceptance credit
|
||||
|
||||
Changes are limited to the S5 wrapper, new pure UID controls and these documents.
|
||||
Actual-Q AST helper loading, finite derived UID planning, import sealing,
|
||||
private-globals phase instrumentation, phase receipts and cleanup rechecks
|
||||
supplement the existing expected inventory. Historical selection, existing
|
||||
require gates, ownership/PID, engine, cache and formal mirror rules remain.
|
||||
The helper is loaded from real Q before controls construct synthetic refs.
|
||||
|
||||
Only py_compile and AST checks are executed and recorded in
|
||||
REPAIR36_STATIC_CHECKS.json. Wrapper fixtures, UID controls, check-only plans,
|
||||
Git negatives and every native diagnostic are unexecuted. No functional pass,
|
||||
full regression, 15+EV batch, original credit or completion is claimed.
|
||||
No Git, engine, Runner or other agent operations were performed. A shell
|
||||
heredoc edit failed before Python execution; edits then used apply_patch.
|
||||
|
||||
Context gap: Q runner API was read from
|
||||
build/owner-handoff/p04-after-p26-closure-r01/q35-uid-diagnostic/run_all_tests.py.reference;
|
||||
Root must confirm the actual Q runner matches that mirror (320ca668…)
|
||||
at runtime. Helper implementation was read from the adjacent P13 reference;
|
||||
runtime loading uses only the actual pinned Q, never either mirror.
|
||||
|
||||
Pending: S5 destruction/midnight/exit drivers; S1–S4/collector fresh Q;
|
||||
derived 184 suites / 329 parse; truthful index; Root exact-candidate qualification.
|
||||
Root order is py_compile → wrapper fixtures → UID controls with explicit scratch
|
||||
→ fresh check-only plan → exactly one new-name diagnostic. The failed r35
|
||||
diagnostic is preserved. All 7 domains + EV, formal 16/88, original 30/88,
|
||||
P04 credit 0, all six D05 approvals pending, M c0ea009 and allowed_paths stay fixed.
|
||||
@@ -15,13 +15,13 @@ all three full lowercase HEX40 inputs. R17 MANIFEST and repair22 power-functions
|
||||
JSON are historical_not_inputs in fresh-Q plans, never fresh-Q fixed pins.
|
||||
No old S1–S4 record is renamed or reused as fresh proof.
|
||||
|
||||
REPAIR35 is check-only only; no native/batch admission until S5
|
||||
REPAIR36 supplies a bounded UID diagnostic, not native/batch admission. Full admission still awaits S5
|
||||
destruction/midnight/exit, S1–S4/collector fresh Q, 184 suites / 329 parse and the
|
||||
truthful index are ready. Root run order and exact-candidate qualification also
|
||||
remain pending. The native implementation is retained for later Root admission;
|
||||
this change and a check-only plan give no admission or acceptance credit.
|
||||
|
||||
After final S35, Root alone performs these steps (not performed by the worker):
|
||||
After the final submission, Root alone prepares Q using these steps (not performed by the worker):
|
||||
|
||||
1. Set S to the final submission and M to
|
||||
`c0ea009b28a7649aca6a433a1a24dc0be5e7ab81`; derive Qt with
|
||||
@@ -31,15 +31,15 @@ After final S35, Root alone performs these steps (not performed by the worker):
|
||||
checkout carrier of Q, never normal Runner C. R34 and Root normal_c_join
|
||||
remain unchanged.
|
||||
3. Stage the s5 directory under Root's own B, the registered BUILD directory.
|
||||
4. Run only the check-only path, with fresh output and plan paths:
|
||||
4. Follow the REPAIR36 order below, with fresh output and plan paths:
|
||||
|
||||
```sh
|
||||
BUILD_OUTPUT_DIR="$B" python3 "$B/.../run_s5_native.py" \
|
||||
--project-root "$wt" --main "$M" --submission "$S" --tested-tree "$Qt" \
|
||||
--check-only --plan "$B/p04-s5-plan-r35.json" --output "$B/p04-s5-native-r35"
|
||||
--check-only --plan "$B/p04-s5-plan-r36.json" --output "$B/p04-s5-DIAG-r36"
|
||||
```
|
||||
|
||||
5. Run `s5_wrapper_fixtures.py` separately. Its JSON always has accepted=false.
|
||||
5. Pure fixtures and controls follow the order below. Their JSON has accepted=false.
|
||||
6. In separate controlled check-only cases, require rejection for: a dirty file;
|
||||
an untracked file; HEAD tree unequal to --tested-tree; wrong --submission;
|
||||
--main unequal to the frozen anchor. Preserve each actual rejection receipt
|
||||
@@ -55,4 +55,34 @@ S5 destruction, midnight and exit cases remain unimplemented. The preserved
|
||||
`PENDING.md` is historical partial31 text; this document records only the added,
|
||||
unexecuted power pair. D05 six approvals, A01, frozen M, 16/88 and P04 credit 0
|
||||
are unchanged. All 7 domains + EV and original 30/88 remain fixed. Root alone
|
||||
performs later qualification; no engine is authorized by REPAIR35.
|
||||
performs later qualification; no engine is authorized for this worker.
|
||||
|
||||
## REPAIR36 UID diagnostic protocol and Root order
|
||||
|
||||
Protocol `p04-s5-fresh-q-uid-diagnostic-v1` is a diagnostic composite with
|
||||
standard_execute_phase_context=false, native_admissible=false and
|
||||
fresh_q_evidence=false. The wrapper extracts only uid_plan and uid_snapshot
|
||||
from the actual pinned Q helper using AST, binding shared to the actual Q
|
||||
runner. It does not execute the helper module. Plans derive finite UID owners
|
||||
from staged refs; import alone seals exact UID bytes. Private function globals
|
||||
replace declared_reports while preserving the execute_phase code object.
|
||||
All four phase UID receipts and the post-cleanup seal are required.
|
||||
Historical mode has no UID instrumentation and remains read-only.
|
||||
|
||||
Root order, all unexecuted by this worker:
|
||||
|
||||
1. py_compile the wrapper and both pure control files.
|
||||
2. Run s5_wrapper_fixtures.py.
|
||||
3. Run `python3 "$B/.../s5_uid_controls.py" --project-root "$wt" --scratch "$B/p04-s5-uid-controls-r36"`.
|
||||
Scratch must be absolute, absent, outside Q, with an existing parent in BUILD.
|
||||
4. Produce a fresh check-only plan with the command above.
|
||||
5. Perform exactly one fresh diagnostic with the identical command and paths,
|
||||
removing only --check-only. Use a new output name; preserve
|
||||
`p04-s5-DIAG-r35` as FAILED. This is a bounded diagnostic, not full admission.
|
||||
|
||||
Root must confirm the actual Q run_all_tests.py matches the supplied reference
|
||||
(sha256 prefix 320ca668); the worker read only the mirror for Q API context.
|
||||
Runtime helper fingerprints and source/provenance guards bind the actual Q.
|
||||
No full regression, 15+EV batch or original credit is claimed. The S5
|
||||
destruction/midnight/exit drivers, S1–S4/collector fresh Q, derived 184 suites /
|
||||
329 parse, truthful index and Root exact-candidate qualification remain pending.
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
"""S5-only native entry. --check-only never loads ownership helpers or starts Godot."""
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
import ast
|
||||
import builtins
|
||||
import inspect
|
||||
import types
|
||||
import copy
|
||||
import hashlib
|
||||
import importlib.util
|
||||
@@ -74,6 +78,74 @@ def pin(path):
|
||||
data = path.read_bytes()
|
||||
return dict(path=str(path), bytes=len(data), sha256=hashlib.sha256(data).hexdigest())
|
||||
|
||||
def load_uid_helper(root, r, refs):
|
||||
hp = root / "tools/run_p13_reference_tests.py"
|
||||
descriptor = pin(hp)
|
||||
r.require(all(descriptor[k] == refs["tools/run_p13_reference_tests.py"][k]
|
||||
for k in ("bytes", "sha256")), "actual Q UID helper pin")
|
||||
src = hp.read_bytes()
|
||||
r.require(len(src) == descriptor["bytes"] and
|
||||
hashlib.sha256(src).hexdigest() == descriptor["sha256"], "stable helper read")
|
||||
tree = ast.parse(src, filename=str(hp))
|
||||
nodes = []
|
||||
for name in ("uid_plan", "uid_snapshot"):
|
||||
matches = [n for n in tree.body if isinstance(n, ast.FunctionDef) and n.name == name]
|
||||
r.require(len(matches) == 1, "exactly one UID helper: " + name)
|
||||
nodes.append(matches[0])
|
||||
ns = {"__builtins__": builtins, "shared": r, "re": re, "stat": stat}
|
||||
exec(compile(ast.Module(body=nodes, type_ignores=[]), str(hp), "exec"), ns)
|
||||
binding = dict(helper_path="tools/run_p13_reference_tests.py",
|
||||
helper_sha256=descriptor["sha256"], helper_bytes=descriptor["bytes"],
|
||||
functions={n.name: hashlib.sha256(ast.get_source_segment(src.decode(), n).encode()).hexdigest()
|
||||
for n in nodes}, shared_module="tools/run_all_tests.py",
|
||||
shared_sha256=r.sha(root / "tools/run_all_tests.py"))
|
||||
return ns["uid_plan"], ns["uid_snapshot"], binding
|
||||
|
||||
|
||||
def make_uid_policy(r, uid_snapshot, source, plan, out):
|
||||
state = dict(source=source, plan=plan, accepted=None, phase=None)
|
||||
|
||||
def reports(stage, exp, previous, requested):
|
||||
r.require(not previous and not requested, "S5 has no generated reports")
|
||||
snap = uid_snapshot(stage, source, plan)
|
||||
if state["accepted"] is None:
|
||||
r.require(state["phase"] == "import", "UID generation only during import")
|
||||
state["accepted"] = snap
|
||||
exp.update({n: {k: p[k] for k in ("bytes", "sha256")} for n, p in snap.items()})
|
||||
r.write(out / "accepted-uids.json", snap)
|
||||
r.require(snap == state["accepted"], "sealed UID bytes unchanged")
|
||||
return r.declared_reports(stage, exp, previous, requested)
|
||||
|
||||
execute = types.FunctionType(r.execute_phase.__code__, dict(vars(r), declared_reports=reports),
|
||||
"execute_phase", r.execute_phase.__defaults__, r.execute_phase.__closure__)
|
||||
r.require(execute.__code__ is r.execute_phase.__code__, "unchanged execute_phase code object")
|
||||
|
||||
def phase_call(*args):
|
||||
stage, phase_out, phase = args[1:4]
|
||||
r.require(phase_out == out, "UID receipt output binding")
|
||||
state["phase"] = phase
|
||||
before, after = None, None
|
||||
try:
|
||||
if phase == "import":
|
||||
r.require(state["accepted"] is None and not (out / "uid-plan.json").exists(), "single UID import")
|
||||
r.require(r.inventory(stage, stage=True) == source, "original stage before import")
|
||||
before = {}
|
||||
r.write(out / "uid-plan.json", plan)
|
||||
else:
|
||||
before = uid_snapshot(stage, source, plan)
|
||||
r.require(before == state["accepted"], "UID set before phase unchanged")
|
||||
row = execute(*args)
|
||||
if row["passed"]:
|
||||
snap = uid_snapshot(stage, source, plan)
|
||||
r.require(snap == state["accepted"], "UID set after phase unchanged")
|
||||
after = snap
|
||||
return row
|
||||
finally:
|
||||
r.write(out / (phase + "-uids.json"), dict(before=before, after=after))
|
||||
|
||||
return reports, phase_call, state
|
||||
|
||||
|
||||
def engine_pin(path, expected=None):
|
||||
path = Path(path)
|
||||
if path != ENGINE or any(p.is_symlink() for p in (path, *path.parents)):
|
||||
@@ -206,6 +278,7 @@ def main():
|
||||
r17_relocation_guard(root)
|
||||
probe_guard(root)
|
||||
expected = {n: dict(bytes=p["bytes"], sha256=p["sha256"]) for n, p in refs.items()}
|
||||
uid_source = copy.deepcopy(expected)
|
||||
contracts_path = root / C_REL if mode == "fresh-q" else CONTRACTS
|
||||
fixed = [pin(p) for p in ([] if mode == "fresh-q" else MATERIALS) + [
|
||||
QA, Path(__file__), HERE / "S5_ROOT_RUN.md",
|
||||
@@ -241,6 +314,19 @@ def main():
|
||||
cache_receipts=cache_receipts, cache_access=cache_note,
|
||||
phases=["import", "parse", "writer", "reader"],
|
||||
native_engine_launches=0, whole_goal_accepted=False, unit_accepted=False)
|
||||
if mode == "fresh-q":
|
||||
uid_plan, uid_snapshot, binding = load_uid_helper(root, r, source_before)
|
||||
uid_plan_map = uid_plan(refs)
|
||||
r.require(len(uid_plan_map) > 0, "nonempty derived UID plan")
|
||||
r.require(all(p["owner"] in refs and p["owner_sha256"] == refs[p["owner"]]["sha256"]
|
||||
for p in uid_plan_map.values()), "UID plan owner bindings")
|
||||
plan.update(protocol="p04-s5-fresh-q-uid-diagnostic-v1", diagnostic_composite=True,
|
||||
standard_execute_phase_context=False, uid_plan=uid_plan_map,
|
||||
uid_plan_count=len(uid_plan_map), instrumentation=dict(
|
||||
wrapper_sha256=r.sha(__file__),
|
||||
execute_phase_source_sha256=hashlib.sha256(inspect.getsource(r.execute_phase).encode()).hexdigest(),
|
||||
declared_reports_source_sha256=hashlib.sha256(inspect.getsource(r.declared_reports).encode()).hexdigest(),
|
||||
callback="private-globals declared_reports + phase wrapper", uid_helper=binding))
|
||||
# Check-only only reads source/materials and writes the plan in task build.
|
||||
# Reads engine identity; never launches Godot or inspects players/processes.
|
||||
if args.check_only:
|
||||
@@ -254,6 +340,7 @@ def main():
|
||||
raise ValueError("historical R17 is read-only")
|
||||
r.require(len(source_before) == provenance["selected_file_count"], "fresh-q selected count")
|
||||
r.require(args.plan.is_file() and r.read(args.plan) == plan, "run exact check-only plan first")
|
||||
reports, phase_call, uid_state = make_uid_policy(r, uid_snapshot, uid_source, plan["uid_plan"], out)
|
||||
engine_observations = []
|
||||
engine_identity = dict(before=engine_descriptor, during=[], after=None)
|
||||
def repin(label):
|
||||
@@ -272,6 +359,9 @@ def main():
|
||||
r.require(fresh_q_guard(root, args.main, args.submission, args.tested_tree) == provenance,
|
||||
"fresh-q provenance changed")
|
||||
probe_guard(root)
|
||||
hp = pin(root / binding["helper_path"])
|
||||
r.require(hp["bytes"] == binding["helper_bytes"] and hp["sha256"] == binding["helper_sha256"],
|
||||
"UID helper unchanged")
|
||||
for value in fixed + cache_receipts:
|
||||
r.require(pin(value["path"]) == value, "fixed input changed: " + value["path"])
|
||||
fixed_guard()
|
||||
@@ -361,6 +451,7 @@ def main():
|
||||
engine_identity_before=engine_descriptor, engine_identity_initial=copy.deepcopy(engine_identity),
|
||||
runner_sha256=r.sha(root / "tools/run_all_tests.py"),
|
||||
default_player_before=protected, fixed_input_pins=fixed,
|
||||
uid_helper=binding, uid_plan=plan["uid_plan"], uid_source_count=len(uid_source),
|
||||
functional_watchdog_seconds=1200, source_adoption=False))
|
||||
diagnostics = module("s5_diagnostics", r.SUPPORT / "diagnostic_gate.py")
|
||||
owners = module("s5_owners", r.SUPPORT / "ordinary_proof_gate.py")
|
||||
@@ -377,7 +468,7 @@ def main():
|
||||
repin("before-" + phase)
|
||||
r.write(out / ("engine-identity-before-" + phase + ".json"),
|
||||
dict(engine_observations[-1], observation_index=len(engine_observations)-1))
|
||||
row = r.execute_phase(str(engine), stage, out, phase, test, selected, expected,
|
||||
row = phase_call(str(engine), stage, out, phase, test, selected, expected,
|
||||
previous, policy, contracts, paths, public, protected, root,
|
||||
outer, markers, diagnostics, owners, audio)
|
||||
phases.append(row)
|
||||
@@ -424,6 +515,9 @@ def main():
|
||||
# Fixed guard always follows ownership cleanup, even if setup or an engine failed.
|
||||
try:
|
||||
fixed_guard()
|
||||
if uid_state["accepted"] is not None:
|
||||
r.require(uid_snapshot(stage, uid_source, plan["uid_plan"]) == uid_state["accepted"],
|
||||
"UID seal after cleanup")
|
||||
after = r.source_refs(root)
|
||||
r.write(out / "source_after.json", after)
|
||||
r.require(after == source_before, "whole product source unchanged")
|
||||
@@ -441,7 +535,10 @@ def main():
|
||||
pids = [p.pid for p in outer.OWNED]
|
||||
passed = (error is None and not guards and not cleanup_errors and len(phases) == 4
|
||||
and all(p["passed"] for p in phases) and len(pids) == len(set(pids)) == 4
|
||||
and all(p["engine_ended"] for p in cleanup))
|
||||
and all(p["engine_ended"] for p in cleanup)
|
||||
and uid_state["accepted"] is not None
|
||||
and set(uid_state["accepted"]) == set(plan["uid_plan"])
|
||||
and all((out / (phase + "-uids.json")).is_file() for phase in plan["phases"]))
|
||||
execution = dict(passed=passed, error=error, guard_errors=guards, phases=phases,
|
||||
actual_captured_PIDs=pids, cleanup=cleanup, cleanup_errors=cleanup_errors,
|
||||
formal_before=formal_before, formal_after=formal_after,
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Pure Root-only UID controls; no engine or environment access."""
|
||||
import argparse
|
||||
import copy
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
sys.dont_write_bytecode = True
|
||||
|
||||
|
||||
def module(name, path):
|
||||
spec = importlib.util.spec_from_file_location(name, path)
|
||||
value = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(value)
|
||||
return value
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--project-root', required=True, type=Path)
|
||||
parser.add_argument('--scratch', required=True, type=Path)
|
||||
args = parser.parse_args()
|
||||
root = args.project_root.resolve(strict=True)
|
||||
r = module('s5_uid_q_runner', root / 'tools/run_all_tests.py')
|
||||
w = module('s5_uid_wrapper', Path(__file__).with_name('run_s5_native.py'))
|
||||
# Actual Q pins precede all synthetic data. No synthetic refs enter the loader.
|
||||
uid_plan, uid_snapshot, binding = w.load_uid_helper(root, r, r.source_refs(root))
|
||||
scratch = args.scratch
|
||||
r.require(scratch.is_absolute() and not scratch.exists() and not scratch.is_symlink(),
|
||||
'absolute fresh scratch')
|
||||
parent = scratch.parent.resolve(strict=True)
|
||||
r.require(parent.is_dir() and parent.is_relative_to(w.BUILD.resolve())
|
||||
and not (parent / scratch.name).is_relative_to(root), 'scratch parent inside BUILD outside Q')
|
||||
scratch = parent / scratch.name
|
||||
scratch.mkdir()
|
||||
results = []
|
||||
|
||||
def fixture(label):
|
||||
stage = scratch / label
|
||||
stage.mkdir()
|
||||
files = {'project.godot': b'config_version=5\n',
|
||||
'scripts/special/peeping_room_service.gd': b'extends Node\n',
|
||||
'tests/special/test_a.gd': b'extends SceneTree\n',
|
||||
'scripts/other.gd': b'extends RefCounted\n',
|
||||
'scripts/other.gd.uid': b'uid://existing\n'}
|
||||
for name, data in files.items():
|
||||
path = stage / name
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_bytes(data)
|
||||
source = r.inventory(stage, stage=True)
|
||||
refs = {n: dict(p, path=str(stage / n)) for n, p in source.items()}
|
||||
plan = uid_plan(refs)
|
||||
r.require(bool(plan) and all(p['owner_sha256'] == refs[p['owner']]['sha256']
|
||||
for p in plan.values()), 'derived synthetic plan')
|
||||
for i, name in enumerate(plan):
|
||||
(stage / name).write_bytes(('uid://generated' + str(i) + '\n').encode())
|
||||
return stage, source, plan
|
||||
|
||||
stage, source, plan = fixture('positive')
|
||||
snap = uid_snapshot(stage, source, plan)
|
||||
r.require(set(snap) == set(plan), 'exact positive planned UID set')
|
||||
results.append('positive')
|
||||
|
||||
def negative(label, mutate):
|
||||
stage, source, plan = fixture(label)
|
||||
names = list(plan)
|
||||
mutate(stage, source, plan, names)
|
||||
try:
|
||||
uid_snapshot(stage, source, plan)
|
||||
except AssertionError:
|
||||
results.append(label)
|
||||
else:
|
||||
raise AssertionError('control did not reject: ' + label)
|
||||
|
||||
negative('extra', lambda s, a, p, n: (s / 'extra.uid').write_bytes(b'uid://extra\n'))
|
||||
negative('original', lambda s, a, p, n: (s / 'project.godot').write_bytes(b'changed\n'))
|
||||
negative('owner', lambda s, a, p, n: (s / p[n[0]]['owner']).write_bytes(b'changed\n'))
|
||||
negative('existing-collision', lambda s, a, p, n: (s / n[0]).write_bytes(b'uid://existing\n'))
|
||||
negative('generated-collision', lambda s, a, p, n: (s / n[0]).write_bytes((s / n[1]).read_bytes()))
|
||||
for label, raw in [('no-newline', b'uid://abc'), ('crlf', b'uid://abc\r\n'),
|
||||
('uppercase', b'uid://ABC\n'), ('too-long', b'uid://abcdefghijklmn\n')]:
|
||||
negative(label, lambda s, a, p, n, raw=raw: (s / n[0]).write_bytes(raw))
|
||||
|
||||
def hardlink(stage, source, plan, names):
|
||||
os.link(stage / names[0], scratch / 'hardlink-peer')
|
||||
|
||||
def symlink(stage, source, plan, names):
|
||||
path = stage / names[0]
|
||||
path.unlink()
|
||||
path.symlink_to(stage / names[1])
|
||||
|
||||
negative('hardlink', hardlink)
|
||||
negative('symlink', symlink)
|
||||
negative('missing', lambda s, a, p, n: (s / n[0]).unlink())
|
||||
stage, source, plan = fixture('post-seal')
|
||||
out = scratch / 'policy-receipts'
|
||||
out.mkdir()
|
||||
reports, phase_call, state = w.make_uid_policy(r, uid_snapshot, source, plan, out)
|
||||
expected = copy.deepcopy(source)
|
||||
state['phase'] = 'import'
|
||||
reports(stage, expected, {}, [])
|
||||
r.require(state['accepted'] == uid_snapshot(stage, source, plan), 'import sealed')
|
||||
state['phase'] = 'parse'
|
||||
(stage / next(iter(plan))).write_bytes(b'uid://mutated\n')
|
||||
try:
|
||||
reports(stage, expected, {}, [])
|
||||
except AssertionError:
|
||||
results.append('post-seal-reports')
|
||||
else:
|
||||
raise AssertionError('post-seal mutation accepted')
|
||||
print(json.dumps({'accepted': False, 'Root-only': True, 'controls': results,
|
||||
'uid_helper': binding, 'scratch': str(scratch)}))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user