mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-09 10:18:32 +01:00
fix(repo-policy): reserve only the two metadata keys, so the _unattributed sentinel stays a valid policy key
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
4732b9dd7a
commit
dd1f942c16
3 files changed
+11
-7
No files matched your search
+1
-1
@@ -5,7 +5,7 @@
|
||||
**A read-only repo can now opt in to Memorable recall, one remote at a time, and a corrupt policy store no longer turns the recall veto off.** #3359 (exGeni) asked for a way to keep a repo out of the brain while still letting its prompts reach Memorable: today the recall hook skips every `deny` and `read-only` repo, and `read-only` is also the tier people pick just to stop code ingest. Garry approved a per-remote flag on 2026-10-24: off by default, and a `deny` always wins. While building the negative controls we found that the hook's policy lookup went through `get`, which quarantines a corrupt store and answers "unset", so a truncated `gbrain-repo-policy.json` let recall run in every repo, read-only and deny included, and reset the store on the way.
|
||||
|
||||
### Added
|
||||
- **`bin/gstack-gbrain-repo-policy memorable set <remote-url> <allow|off>`** stores the opt-in under a reserved `_memorable_recall` map in the policy store. It is refused unless the remote is read-only (deny vetoes recall; read-write never needed it). `memorable get [<remote-url>]` prints `<tier>\t<allow|off>`, and `list` adds a `memorable=allow` column. Changing a remote's tier clears its opt-in, and keys starting with `_` are refused as remotes.
|
||||
- **`bin/gstack-gbrain-repo-policy memorable set <remote-url> <allow|off>`** stores the opt-in under a reserved `_memorable_recall` map in the policy store. It is refused unless the remote is read-only (deny vetoes recall; read-write never needed it). `memorable get [<remote-url>]` prints `<tier>\t<allow|off>`, and `list` adds a `memorable=allow` column. Changing a remote's tier clears its opt-in, and the two metadata keys (`_schema_version`, `_memorable_recall`) are refused as remotes.
|
||||
- **`lib/gbrain-repo-policy-client.ts`**: `memorableRecallPolicy(url)` returns the tier and the opt-in in one spawn. Anything but exactly `<tier>\t<allow|off>` reads as `unreadable`.
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -48,7 +48,8 @@
|
||||
# "github.com/baz/qux": "deny",
|
||||
# "_memorable_recall": { "github.com/foo/bar": "allow" }
|
||||
# }
|
||||
# Keys starting with "_" are reserved and never name a remote.
|
||||
# The keys _schema_version and _memorable_recall are reserved; other keys
|
||||
# name remotes (including the _unattributed sentinel memory-ingest uses).
|
||||
#
|
||||
# Tier semantics:
|
||||
# read-write — agent may search AND write new pages from this repo.
|
||||
@@ -216,11 +217,11 @@ memorable_optin() {
|
||||
# jq filter that removes $key's opt-in (and an emptied map).
|
||||
DROP_MEMORABLE_OPTIN='if (._memorable_recall | type) == "object" then (._memorable_recall |= del(.[$key])) | (if ._memorable_recall == {} then del(._memorable_recall) else . end) else . end'
|
||||
|
||||
# Keys starting with "_" hold store metadata (_schema_version,
|
||||
# _memorable_recall); a remote that normalizes to one cannot be stored.
|
||||
# _schema_version and _memorable_recall hold store metadata; a remote that
|
||||
# normalizes to one of them cannot be stored.
|
||||
reject_reserved_key() {
|
||||
case "$1" in
|
||||
_*) die "'$1' is a reserved key in the policy store, not a remote" ;;
|
||||
_schema_version|_memorable_recall) die "'$1' is a reserved key in the policy store, not a remote" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
@@ -456,7 +457,7 @@ cmd_list() {
|
||||
fi
|
||||
ensure_file
|
||||
jq -r '(._memorable_recall | if type == "object" then . else {} end) as $m
|
||||
| to_entries[] | select(.key | startswith("_") | not)
|
||||
| to_entries[] | select(.key != "_schema_version" and .key != "_memorable_recall")
|
||||
| "\(.key)\t\(.value)" + (if $m[.key] == "allow" then "\tmemorable=allow" else "" end)' "$POLICY_FILE" | sort
|
||||
}
|
||||
|
||||
|
||||
@@ -526,9 +526,12 @@ describe('memorable recall opt-in (#3359)', () => {
|
||||
expect(r.stderr).toContain('not a readable file');
|
||||
});
|
||||
|
||||
test('reserved keys are never stored as remotes', () => {
|
||||
test('the two metadata keys are never stored as remotes; the _unattributed sentinel still is', () => {
|
||||
const r = run(['set', '_memorable_recall', 'read-write']);
|
||||
expect(r.status).toBe(2);
|
||||
expect(r.stderr).toContain('reserved key');
|
||||
expect(run(['set', '_schema_version', 'deny']).status).toBe(2);
|
||||
expect(run(['set', '_unattributed', 'deny']).status).toBe(0);
|
||||
expect(run(['list']).stdout).toBe('_unattributed\tdeny');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user