Provision the E2E memory secret into the local vault

`nap gateway vault setup` unwraps the project memory secret once (prompt
on a terminal, or the existing argument/env paths) and stores the
secret, never the passphrase, in memory-secrets.vault.json under the
existing 0600 local vault key. The CLI and MCP workers load it
automatically and MCP never prompts, per
/decisions/local-gateway-no-interactive-unlock and
/decisions/2026-09-29-memory-secret-local-vault. Older versions stay
readable; a rotated active version reports memory_secret_rotated with
the setup next action. `vault forget` revokes local access, including
for running workers. Env passphrases still work, are persisted into the
vault, and are reported as deprecated. Search warns
e2e_index_not_provisioned instead of e2e_index_locked. Local key
creation is 0600 from the start and never replaces a published key.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
HumbleTurtle
2026-09-29 00:49:48 -03:00
co-authored by Claude Opus 5.5
parent 611a4571f3
commit eed1d1d3f2
7 changed files with 1495 additions and 64 deletions
+7 -4
View File
@@ -229,20 +229,23 @@ def test_e2e_body_term_is_findable_with_snippet_while_unlocked(env):
assert not discovered.get("warnings")
def test_locked_secret_yields_no_e2e_hits_and_an_explicit_warning(env):
def test_unprovisioned_secret_yields_no_e2e_hits_and_an_explicit_warning(env):
mod, provider, _ = env
seed(mod, provider)
lock(mod)
local = local_search(mod, BODY_TERM)
assert hit_ids(local) == []
assert codes(local) == ["e2e_index_locked"]
assert codes(local) == ["e2e_index_not_provisioned"]
warning = local["warnings"][0]
assert warning["memory_secret"] == "not_provisioned"
assert warning["next_action"] == "nap gateway vault setup"
response = mod.search_memory({"q": BODY_TERM, "mode": "local", "view": "summary"})
assert response["items"] == []
assert "e2e_index_locked" in codes(response)
assert "e2e_index_not_provisioned" in codes(response)
# Identity fields of the E2E node remain searchable from the main index.
assert hit_ids(local_search(mod, "secretnote")) == ["secretnote"]
# A locked reindex never prompts and writes no shard.
# An unprovisioned reindex never prompts and writes no shard.
shard_file(mod).unlink()
assert "e2e_index" in mod.reindex_project({})
assert not shard_file(mod).exists()