Skip to content

Commit e8080bd

Browse files
authored
Merge pull request #151 from ConductionNL/fix/register-authorization-not-publicread
fix(register): the template taught publicRead and never taught authorization
2 parents abfb1ca + a0a5581 commit e8080bd

3 files changed

Lines changed: 61 additions & 10 deletions

File tree

README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,44 @@ _Update this diagram during `/app-explore` sessions as the architecture evolves.
6666

6767
_Data model is defined using OpenRegister schemas. See [`openspec/specs/`](openspec/specs/) for feature-level design decisions and [`openspec/architecture/`](openspec/architecture/) for architectural decisions._
6868

69+
#### Who can read a schema
70+
71+
Declare an `authorization` block on **every** schema. Access is decided by
72+
OpenRegister's RBAC groups and by nothing else — `public` is a special group
73+
meaning "an anonymous visitor", and `authenticated` means "any logged-in user".
74+
75+
```jsonc
76+
// authenticated users only — the safe default, and what this template ships
77+
"authorization": { "read": ["authenticated"] }
78+
79+
// genuinely public content
80+
"authorization": { "read": ["public"] }
81+
82+
// public, but only once a condition holds — e.g. a publication that is live.
83+
// RBAC then answers "may they read it" and "is it ready" in one place, instead
84+
// of every call site having to remember the second question.
85+
"authorization": {
86+
"read": [
87+
{ "group": "public", "match": { "status": "published" } },
88+
"authenticated"
89+
]
90+
}
91+
92+
// a named group, for role-gated data
93+
"authorization": { "read": ["some-group-id"] }
94+
```
95+
96+
> ⚠️ **`x-openregister.publicRead` / `publicWrite` are not a thing.** Earlier
97+
> versions of this template shipped them and they are not part of
98+
> OpenRegister's schema contract — nothing reads them, so a schema marked
99+
> `"publicRead": false` was never protected by that line. They have been
100+
> removed. If you find them in an app, replace them with an `authorization`
101+
> block.
102+
103+
> ⚠️ **A schema that declares nothing inherits a default**, which is not a
104+
> decision anyone made about your data. Declare the block even when the answer
105+
> is the boring one.
106+
69107
### Directory Structure
70108

71109
```

lib/Settings/apptemplate_register.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@
2121
"icon": "FileDocumentOutline",
2222
"version": "0.1.0",
2323
"title": "Example",
24-
"description": "Example schema — replace with your app's actual schemas.",
24+
"description": "Example schema — replace with your app's actual schemas. NOTE the `authorization` block below: declare one on EVERY schema you add. A schema that declares none inherits whatever OpenRegister's default happens to be, which is not a decision anyone made about your data.",
2525
"type": "object",
2626
"required": [
2727
"title"
2828
],
29-
"x-openregister": {
30-
"publicRead": false,
31-
"publicWrite": false
29+
"authorization": {
30+
"read": [
31+
"authenticated"
32+
]
3233
},
3334
"properties": {
3435
"title": {

tests/validate-register.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -187,13 +187,25 @@ function validateRegister(file, errors, warnings) {
187187
`${at}: "properties" is empty — schema looks clobbered (a merge may have replaced it with a stub)`,
188188
)
189189
// "too thin to be real" heuristic: a schema that declares a lifecycle/calc/notif/agg
190-
// elsewhere but here has ≤3 properties and no x-openregister-* at all is suspect.
190+
// elsewhere but here has ≤3 properties and nothing else declared at all is suspect.
191+
//
192+
// `authorization` counts as a declaration. It used not to, and that was
193+
// an incentive in the wrong direction: removing a bogus
194+
// `x-openregister: { publicRead: … }` block — which is NOT part of
195+
// OpenRegister's schema contract and is read by nothing — made this
196+
// warning fire, so the tooling rewarded keeping it. Declaring who may
197+
// read a schema is at least as strong a sign of a real schema as
198+
// declaring a seed.
191199
const xKeys = Object.keys(s).filter((k) => k.startsWith('x-openregister'))
192-
if (
193-
props.length > 0
194-
&& props.length <= 3
195-
&& xKeys.filter((k) => k !== 'x-openregister-seed').length === 0
196-
) {
200+
// Boolean() is load-bearing: `s.authorization && …` yields `undefined`
201+
// when the key is absent, and `undefined === false` is FALSE — so a
202+
// strict comparison here silently disabled the whole heuristic. Caught
203+
// by feeding it a genuine stub, which it then failed to flag.
204+
const declaresSomething = Boolean(
205+
xKeys.filter((k) => k !== 'x-openregister-seed').length > 0
206+
|| (s.authorization && typeof s.authorization === 'object'),
207+
)
208+
if (props.length > 0 && props.length <= 3 && declaresSomething === false) {
197209
warnings.push(
198210
`${at}: only ${props.length} properties and no x-openregister-* declarations — verify this isn't a stub left by a bad merge`,
199211
)

0 commit comments

Comments
 (0)