Seal ignored-workspace routing at Domain startup
This commit is contained in:
parent
b114e3514b
commit
1ad3b84db2
3 changed files with 720 additions and 285 deletions
|
|
@ -44,19 +44,18 @@
|
|||
},
|
||||
{
|
||||
"id": "ignored-to-host-policy",
|
||||
"trigger": "path becomes non-ignored without becoming tracked",
|
||||
"trigger": "next Domain initialization classifies an isolated path as host-backed",
|
||||
"new_lookups": "host-or-absent",
|
||||
"open_handles": "remain-isolated",
|
||||
"isolated_state": "retained-hidden",
|
||||
"isolated_state": "deleted-before-readiness",
|
||||
"copy": "none"
|
||||
},
|
||||
{
|
||||
"id": "host-to-ignored-policy",
|
||||
"trigger": "untracked path becomes ignored",
|
||||
"new_lookups": "retained-isolated-or-absent",
|
||||
"open_handles": "remain-host",
|
||||
"host_state": "retained-hidden",
|
||||
"copy": "none"
|
||||
"trigger": "next Domain initialization classifies a host-backed path as ignored",
|
||||
"new_lookups": "host-clone-or-absent",
|
||||
"host_state": "retained-unchanged",
|
||||
"isolated_state": "host-clone-replaces-stale-state",
|
||||
"copy": "host-to-isolated-only"
|
||||
},
|
||||
{
|
||||
"id": "isolated-to-tracked-guest-publication",
|
||||
|
|
@ -65,22 +64,6 @@
|
|||
"index_mutation": "none",
|
||||
"isolated_state": "retained-visible",
|
||||
"copy": "none"
|
||||
},
|
||||
{
|
||||
"id": "isolated-to-tracked-host-established",
|
||||
"trigger": "published index and type-compatible host object both exist",
|
||||
"new_lookups": "host",
|
||||
"open_handles": "remain-isolated",
|
||||
"isolated_state": "retained-hidden",
|
||||
"copy": "none"
|
||||
},
|
||||
{
|
||||
"id": "isolated-to-tracked-unmediated-inconsistent",
|
||||
"trigger": "unmediated index publication tracks a path without a host object",
|
||||
"result": "EIO",
|
||||
"path_state": "fail-closed-until-consistent",
|
||||
"isolated_state": "retained-hidden-recoverable",
|
||||
"copy": "none"
|
||||
}
|
||||
],
|
||||
"filesystem_operations": [
|
||||
|
|
|
|||
50
tests/fixtures/ignored-workspace-v1/corpus.json
vendored
50
tests/fixtures/ignored-workspace-v1/corpus.json
vendored
|
|
@ -67,12 +67,12 @@
|
|||
"expect": ["nested-rules-selected", "host-sentinel-hidden"]
|
||||
},
|
||||
{
|
||||
"id": "live-ignore-publication",
|
||||
"tags": ["ignore-precedence", "live-policy-change", "concurrent-mutation"],
|
||||
"id": "startup-sealed-ignore-mutation",
|
||||
"tags": ["ignore-precedence", "startup-sealed-policy", "concurrent-mutation"],
|
||||
"path_hex": "67656e6572617465642f6f7574707574",
|
||||
"setup": ["host-object", "path-initially-non-ignored"],
|
||||
"actions": ["host-publish-ignore", "sandbox-open-after-publication"],
|
||||
"expect": ["single-classification-epoch", "host-object-hidden", "no-copy"]
|
||||
"actions": ["host-mutate-ignore", "sandbox-open-in-same-generation"],
|
||||
"expect": ["single-classification-epoch", "host-object-remains-visible", "no-copy"]
|
||||
},
|
||||
{
|
||||
"id": "cargo-target-host-to-isolated-rename",
|
||||
|
|
@ -108,19 +108,19 @@
|
|||
},
|
||||
{
|
||||
"id": "ignored-becomes-non-ignored",
|
||||
"tags": ["ignored-to-tracked-transition", "open-handle-transition", "no-copy-back"],
|
||||
"tags": ["startup-policy-transition", "no-copy-back"],
|
||||
"path_hex": "63616368652f64617461",
|
||||
"setup": ["isolated-object", "host-object", "open-isolated-handle"],
|
||||
"actions": ["host-negate-ignore", "sandbox-open-new", "write-old-handle"],
|
||||
"expect": ["new-handle-host", "old-handle-isolated", "no-copy", "both-objects-retained"]
|
||||
"setup": ["isolated-object", "host-object", "path-ignored"],
|
||||
"actions": ["stop-domain", "host-negate-ignore", "start-domain"],
|
||||
"expect": ["host-object-visible", "isolated-object-deleted", "no-copy-back"]
|
||||
},
|
||||
{
|
||||
"id": "non-ignored-becomes-ignored",
|
||||
"tags": ["ignored-to-tracked-transition", "open-handle-transition", "no-copy-back"],
|
||||
"tags": ["startup-policy-transition", "host-to-isolated-copy", "no-copy-back"],
|
||||
"path_hex": "6f75742f64617461",
|
||||
"setup": ["host-object", "retained-isolated-object", "open-host-handle"],
|
||||
"actions": ["host-publish-ignore", "sandbox-open-new", "write-old-handle"],
|
||||
"expect": ["new-handle-isolated", "old-handle-host", "no-copy", "both-objects-retained"]
|
||||
"setup": ["host-object", "stale-isolated-object", "path-initially-non-ignored"],
|
||||
"actions": ["stop-domain", "host-publish-ignore", "start-domain"],
|
||||
"expect": ["isolated-clone-visible", "stale-isolated-replaced", "host-object-unchanged"]
|
||||
},
|
||||
{
|
||||
"id": "guest-force-add-isolated-only",
|
||||
|
|
@ -132,35 +132,35 @@
|
|||
},
|
||||
{
|
||||
"id": "host-established-tracked-cutover",
|
||||
"tags": ["ignored-to-tracked-transition", "open-handle-transition", "no-copy-back"],
|
||||
"tags": ["ignored-to-tracked-transition", "startup-policy-transition", "no-copy-back"],
|
||||
"path_hex": "6173736574732f67656e657261746564",
|
||||
"setup": ["isolated-object", "open-isolated-handle"],
|
||||
"actions": ["host-create-type-compatible-object", "host-publish-tracked-index", "sandbox-open-new"],
|
||||
"expect": ["new-handle-host", "old-handle-isolated", "isolated-object-retained-hidden", "no-copy"]
|
||||
"setup": ["isolated-object", "path-ignored"],
|
||||
"actions": ["host-create-type-compatible-object", "host-publish-tracked-index", "sandbox-open-in-same-generation", "restart-domain"],
|
||||
"expect": ["same-generation-route-isolated", "next-generation-route-host", "isolated-object-deleted", "no-copy-back"]
|
||||
},
|
||||
{
|
||||
"id": "unmediated-inconsistent-index",
|
||||
"tags": ["ignored-to-tracked-transition", "no-silent-loss", "concurrent-mutation"],
|
||||
"tags": ["ignored-to-tracked-transition", "startup-policy-transition", "no-silent-loss", "concurrent-mutation"],
|
||||
"path_hex": "646570732f6c6962",
|
||||
"setup": ["isolated-object", "host-path-absent"],
|
||||
"actions": ["host-publish-tracked-index", "sandbox-lookup"],
|
||||
"expect": ["EIO", "path-fail-closed", "isolated-object-recoverable", "host-path-absent"]
|
||||
"actions": ["host-publish-tracked-index", "sandbox-lookup-in-same-generation", "restart-domain"],
|
||||
"expect": ["same-generation-route-isolated", "next-generation-path-absent", "isolated-object-deleted", "host-path-absent"]
|
||||
},
|
||||
{
|
||||
"id": "mmap-policy-transition",
|
||||
"tags": ["mmap", "open-handle-transition", "no-copy-back"],
|
||||
"tags": ["mmap", "startup-sealed-policy", "no-copy-back"],
|
||||
"path_hex": "63616368652f6d6170706564",
|
||||
"setup": ["isolated-object", "shared-write-mapping"],
|
||||
"actions": ["host-negate-ignore", "mapped-write", "mapping-sync"],
|
||||
"expect": ["isolated-object-updated", "host-object-unchanged", "no-copy"]
|
||||
"expect": ["same-generation-route-isolated", "isolated-object-updated", "host-object-unchanged", "no-copy"]
|
||||
},
|
||||
{
|
||||
"id": "locks-policy-transition",
|
||||
"tags": ["locks", "open-handle-transition"],
|
||||
"tags": ["locks", "startup-sealed-policy"],
|
||||
"path_hex": "63616368652f6c6f636b6564",
|
||||
"setup": ["isolated-object", "isolated-posix-lock", "host-object"],
|
||||
"actions": ["host-negate-ignore", "sandbox-open-new", "host-lock-attempt"],
|
||||
"expect": ["old-lock-remains-isolated", "new-lock-domain-host", "no-lock-transfer"]
|
||||
"expect": ["same-generation-lock-domain-isolated", "host-lock-domain-independent", "no-lock-transfer"]
|
||||
},
|
||||
{
|
||||
"id": "extended-attributes-and-acls",
|
||||
|
|
@ -204,11 +204,11 @@
|
|||
},
|
||||
{
|
||||
"id": "directory-stream-policy-snapshot",
|
||||
"tags": ["concurrent-mutation", "open-handle-transition", "ignore-precedence"],
|
||||
"tags": ["concurrent-mutation", "startup-sealed-policy", "ignore-precedence"],
|
||||
"path_hex": "6f7574",
|
||||
"setup": ["open-directory-stream", "host-and-isolated-children"],
|
||||
"actions": ["host-publish-ignore-change", "continue-readdir", "open-new-directory-stream"],
|
||||
"expect": ["old-stream-single-snapshot", "new-stream-new-snapshot", "no-duplicate-name"]
|
||||
"expect": ["old-stream-single-snapshot", "new-stream-same-generation-snapshot", "no-duplicate-name"]
|
||||
},
|
||||
{
|
||||
"id": "git-ordinary-workflow",
|
||||
|
|
|
|||
|
|
@ -179,14 +179,17 @@ class IgnoredWorkspaceContractTests(unittest.TestCase):
|
|||
self.assertEqual(transitions["cross-route-hard-link"]["result"], "EXDEV")
|
||||
self.assertEqual(transitions["rename-whiteout"]["result"], "EOPNOTSUPP")
|
||||
|
||||
def test_transitions_never_copy_or_rebind_open_handles(self) -> None:
|
||||
def test_transitions_copy_only_toward_isolated_state_between_generations(self) -> None:
|
||||
transitions = load("contract.json")["transition_contracts"]
|
||||
copying = [
|
||||
transition["id"]
|
||||
for transition in transitions
|
||||
if "copy" in transition and transition["copy"] != "none"
|
||||
]
|
||||
self.assertEqual(copying, ["qualified-host-to-isolated-rename"])
|
||||
self.assertEqual(
|
||||
copying,
|
||||
["qualified-host-to-isolated-rename", "host-to-ignored-policy"],
|
||||
)
|
||||
handle_transitions = {
|
||||
transition["id"]: transition["open_handles"]
|
||||
for transition in transitions
|
||||
|
|
@ -194,11 +197,7 @@ class IgnoredWorkspaceContractTests(unittest.TestCase):
|
|||
}
|
||||
self.assertEqual(
|
||||
handle_transitions,
|
||||
{
|
||||
"ignored-to-host-policy": "remain-isolated",
|
||||
"host-to-ignored-policy": "remain-host",
|
||||
"isolated-to-tracked-host-established": "remain-isolated",
|
||||
},
|
||||
{},
|
||||
)
|
||||
|
||||
def test_isolated_only_force_add_is_explicitly_refused(self) -> None:
|
||||
|
|
@ -251,19 +250,18 @@ class IgnoredWorkspaceContractTests(unittest.TestCase):
|
|||
},
|
||||
{
|
||||
"id": "ignored-to-host-policy",
|
||||
"trigger": "path becomes non-ignored without becoming tracked",
|
||||
"trigger": "next Domain initialization classifies an isolated path as host-backed",
|
||||
"new_lookups": "host-or-absent",
|
||||
"open_handles": "remain-isolated",
|
||||
"isolated_state": "retained-hidden",
|
||||
"isolated_state": "deleted-before-readiness",
|
||||
"copy": "none",
|
||||
},
|
||||
{
|
||||
"id": "host-to-ignored-policy",
|
||||
"trigger": "untracked path becomes ignored",
|
||||
"new_lookups": "retained-isolated-or-absent",
|
||||
"open_handles": "remain-host",
|
||||
"host_state": "retained-hidden",
|
||||
"copy": "none",
|
||||
"trigger": "next Domain initialization classifies a host-backed path as ignored",
|
||||
"new_lookups": "host-clone-or-absent",
|
||||
"host_state": "retained-unchanged",
|
||||
"isolated_state": "host-clone-replaces-stale-state",
|
||||
"copy": "host-to-isolated-only",
|
||||
},
|
||||
{
|
||||
"id": "isolated-to-tracked-guest-publication",
|
||||
|
|
@ -273,22 +271,6 @@ class IgnoredWorkspaceContractTests(unittest.TestCase):
|
|||
"isolated_state": "retained-visible",
|
||||
"copy": "none",
|
||||
},
|
||||
{
|
||||
"id": "isolated-to-tracked-host-established",
|
||||
"trigger": "published index and type-compatible host object both exist",
|
||||
"new_lookups": "host",
|
||||
"open_handles": "remain-isolated",
|
||||
"isolated_state": "retained-hidden",
|
||||
"copy": "none",
|
||||
},
|
||||
{
|
||||
"id": "isolated-to-tracked-unmediated-inconsistent",
|
||||
"trigger": "unmediated index publication tracks a path without a host object",
|
||||
"result": "EIO",
|
||||
"path_state": "fail-closed-until-consistent",
|
||||
"isolated_state": "retained-hidden-recoverable",
|
||||
"copy": "none",
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
|
|
@ -372,7 +354,9 @@ class IgnoredWorkspaceContractTests(unittest.TestCase):
|
|||
"concurrent-mutation",
|
||||
"cross-policy-rename",
|
||||
"ignored-to-tracked-transition",
|
||||
"open-handle-transition",
|
||||
"startup-sealed-policy",
|
||||
"startup-policy-transition",
|
||||
"host-to-isolated-copy",
|
||||
"no-silent-loss",
|
||||
"no-copy-back",
|
||||
}
|
||||
|
|
@ -384,7 +368,7 @@ class IgnoredWorkspaceContractTests(unittest.TestCase):
|
|||
cases["cross-route-file-rename"]["expect"],
|
||||
["EXDEV", "source-unchanged", "destination-absent"],
|
||||
)
|
||||
self.assertIn("isolated-object-recoverable", cases["unmediated-inconsistent-index"]["expect"])
|
||||
self.assertIn("isolated-object-deleted", cases["unmediated-inconsistent-index"]["expect"])
|
||||
self.assertIn("access-error-not-host-fallback", cases["router-loss-fails-closed"]["expect"])
|
||||
self.assertIn("host-sentinel-unchanged", cases["router-loss-fails-closed"]["expect"])
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue