You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 89c2ba9
Browse filesBrowse the repository at this point in the historyBrowse files
test(rest): pin /audit as the third authoring door; changeset and docs
The real-stack authoring-door file now runs every refusal, builder and
one-predicate pin over /diff, /history and /audit, with the drafts saved
by an author. The census row for /audit turns authoring, and the two
/audit route tests whose question is an admitted caller's now call as one.
Claude-Session: https://claude.ai/code/session_local_1d2a197c-c20e-4e90-9be8-413d4d432289
Co-authored-by: Claude <noreply@anthropic.com>
**`GET /api/v1/meta/:type/:name/audit` is now an authoring door: a caller without an authoring capability is refused, as `/diff`, `/history` and `GET /api/v1/meta/_drafts` refuse.** Before this release, any signed-in caller who could open an item could read its protection-audit trail. Every save appends a row to that trail, a draft save included, and the row carries `note: "draft"`, the actor and the time. So a member could learn that an item had unpublished authoring work, who saved it and when. For an item that had never been published, where the plain read answers `404`, the member could learn that it existed at all. This carries the maintainer's ruling on #20378 (letter B, comment 5865708652) to this door, as triage graded on #20441: draft and preview reads are admin-gated upstream (ADR-0106 D4), and the audit trail, like the version log, has no published-only answer to fall back to.
6
+
7
+
Clause-②: no
8
+
9
+
-**Who may read it:** a system context, or a caller holding `studio.access`, `setup.access` or `manage_metadata`. This is the predicate `/meta/_drafts`, `/diff`, `/history` and every draft switch already ask, not a second rule.
10
+
-**Everyone else:**`403` with code `FORBIDDEN`, in the same nested `error` envelope `/meta/_drafts` answers. The refusal is decided on the caller before the protocol is resolved, before the query is parsed and before any event is read. So it is the same answer for an item that exists, one that does not, and one that exists only as a draft, and it carries no event, actor or item name. The message names the door, not drafts.
11
+
-**Unchanged:** callers with an authoring capability read the trail exactly as before, including the per-caller refusal of an item the plain read refuses them and the organization scope of the read.
12
+
13
+
A client that read `/audit` (`client.meta.getAudit`) as a member now receives `403 FORBIDDEN`. To read it, call as a caller holding one of the three capabilities above.
describe('[#20378] a member without an authoring capability is refused /diffand /history — the /meta/_drafts refusal, before any read',()=>{
248
+
describe('[#20378 · #20441] a member without an authoring capability is refused /diff, /history and /audit — the /meta/_drafts refusal, before any read',()=>{
it(`${suffix}${type}: 403 FORBIDDEN in the /meta/_drafts envelope — one answer for a published item, a draft-only one and a missing name, and nothing read`,async()=>{
@@ -245,10 +266,10 @@ describe('[#20378] a member without an authoring capability is refused /diff and
245
266
// `error` with a code and a message, and nothing beside it.
246
267
expect(shape(res)).toEqual(shape(listing));
247
268
// No item or version detail: not the name, not a draft
248
-
// string, not a version, not an event.
269
+
// string, not a version, not an event, not its actor.
0 commit comments