Summary#
osy explain is the report a reviewer reads to answer who can reach what. Besides stating every rule, it flags the
places where a page's or a topic's access looks wrong. When one of those is what you meant, say so where it is
declared, and say why:
[Intended("public-page-gated-data", Justification = "Visitors see the welcome; members see the notes.")]
[AllowAnonymous, Route("/")]
component Welcome() { … }The finding is still in the report — as ✓ intended, with your reason beside it — and the count at the top of the
report reads 0 open.
Signature#
[Intended("<finding>", Justification = "<why>")] // on a component (a page) or a topic — one per finding| on | <finding> | flagged when |
|---|---|---|
| a page | public-page-gated-data | an [AllowAnonymous] page reads an entity a signed-out visitor may not read |
| a page | page-auth-broader-than-data | a page any signed-in user may open reads an entity gated by a role or policy |
| a page | reads-ungranted-entity | a page reads an entity that grants read to nobody |
| a topic | topic-open-to-anonymous | an [AllowAnonymous] topic: a caller with no account may join and publish |
| a topic | candidates-ask-nothing-about-who | its Candidates never reads the caller, so it answers the same for everyone |
| a topic | publishers-ask-nothing-about-who | its Publishers never reads the caller |
Description#
It acknowledges; it does not hide#
An acknowledged finding stays in the Markdown and in osy explain --json. The Markdown says it as decided:
- **Reads** — Note
- ✓ intended — 'Welcome' is public ([AllowAnonymous]) but 'Note' is not anonymously readable — the page renders
and the read returns zero rows (a silent empty page). _Acknowledged (`public-page-gated-data`): Visitors see the
welcome; members see the notes._and the JSON carries the reason on the finding ("acknowledged": "Visitors see the welcome; …"), with the report's
openFindings and acknowledgedFindings beside it. So a reviewer reads the posture and the decision together, and a
report with zero open findings is one where every flag was looked at — not one where flags were switched off.
One finding, with a reason#
The mark names exactly one finding, so a different one that appears on the same page later is not acknowledged in
advance; write one [Intended] per finding you mean. The reason is required. An [Intended] that names no finding the
page or topic can carry is refused with the list above; one with no Justification is refused, because the reason is
what the report prints.
A mark that no longer matches is reported#
If the page stops having the finding — the entity became readable, the page gained a gate — the mark is left
acknowledging nothing. The report flags it as open (stale-acknowledgement): delete it, or it will quietly acknowledge
the next finding of that kind.
What it is not for#
- A sentence marked
(needs review)is the report failing to phrase a rule — the platform's to fix, not yours to accept — and no attribute applies to it. - An
osy lintfinding is decided with[SuppressWarning("<rule>")](a MUST-tier one cannot be). An[Intended]naming a lint rule is refused, saying so. - It changes nothing about who can do what. Access is still exactly what the rules say.
Examples#
[Principal] entity User {
[Unique, MaxLength(200)] string Email;
security { allow read when IsAuthenticated; }
}
entity Note {
[MaxLength(200)] string Body = "";
security { allow read when IsAuthenticated; }
}
[Intended("public-page-gated-data", Justification = "Visitors see the welcome; members see the notes.")]
[AllowAnonymous, Route("/")]
component Welcome() {
render {
Stack {
Text("Welcome.");
foreach (var n in Note.ToList()) { Text(n.Body); }
}
}
}
class StatusLine { public string Text = ""; }
[Intended("topic-open-to-anonymous", Justification = "The service status banner is public by design.")]
[AllowAnonymous]
topic ServiceStatus() {
Candidates = u => u == null || u.Email != "";
Carries = StatusLine;
}osy explain on it opens with > **Findings:** 0 open · 2 acknowledged as intended.
See also#
- Explaining your app's security — the report these findings are in
- public pages (what a signed-out visitor can see and do) — making an entity readable to visitors, when the page should show it to them
- topic —
Candidates,Publishersand[AllowAnonymous]on a topic - Checking your app —
osy lint, and[SuppressWarning]for its advice