Example
Worked application · access check
A support route missing its role check
A delivery company gives customers a case view and its support team a workspace with private notes. The application logic is written in Bosatsu, a typed functional language whose compiled structure Yichus can inspect. A maintenance shortcut accidentally makes the privileged review helper reachable from an ordinary authenticated route.
This is a complete five-route component. You can run its customer behavior, inspect both full programs, reproduce the static finding, make edits, and hand the repair to a connected agent in the same page.
Application and access requirements
Customers use their normal account. Support workers use the staff workflow.
One support_cases table holds the owner id, public case fields, and
a private staff note.
- A customer may view or reply only when
owns_caseconfirms the stored case names that caller. - A support worker may review the full case and resolve it only through routes requiring
support. /staff/quick-reviewremains available with the same staff role requirement.- Route declarations continue to list the reads and writes their handlers perform.
The policy stays GuardedOrRoles(["owns_case"], ["support"])
before and after the repair. It permits the customer path under the ownership
guard and the staff path when every reaching route requires the role.
| Route | User | Access path |
|---|---|---|
/cases/view | Customer | Read a row, use it only after owns_case |
/cases/reply | Customer | Read a row, then use and write it after owns_case |
/staff/review | Support | Role-protected private review |
/staff/resolve | Support | Role-protected read and write |
/staff/quick-review | Support | The route repaired below |
The flawed application
The ordinary route still requires some authenticated caller at
the server boundary, but it does not require that caller to have the
support role. It reaches review_case, then
load_for_staff, which returns the private note without the
customer ownership guard.
route("/staff/quick-review", handler("review_case", review_case),
[ReadPerm("support_cases")]),
Open the complete flawed Bosatsu source. The other four routes, both customer handlers, the staff handlers, the table, and the access policy are all present in that file.
The exact check and its recorded result
The featured request runs api_access_check on the complete flawed
source. It is a static analysis over typed compiled IR; it does not execute a
login or sample users.
api_access_check({
"sources": [{
"fileName": "support-access-before.bosatsu",
"source": COMPLETE_LINKED_SOURCE
}]
})
Exact request with the full source · complete captured response
Tool report — recorded: support_cases is
violated. The response includes this verbatim finding:
{
"binding": "load_for_staff",
"resource": "support_cases",
"operation": "use",
"kind": "RowEscapesGuard",
"status": "violated",
"detail": "a value derived from a row of \"support_cases\" is returned outside any branch on owns_case applied to Principal.user_id and the row"
}
Author’s interpretation: the row escape is expected inside the privileged staff helper, but the role bypass cannot apply because an ordinary route also reaches that helper. The report does not say that authentication is absent. It says the declared ownership-or-role policy is not established on every path.
Repair the route, preserve the policy
The repair changes only the shortcut declaration. It keeps the useful route, handler behavior, permissions, ownership guard, and access policy.
- route("/staff/quick-review", handler("review_case", review_case),
+ role_route("/staff/quick-review", handler("review_case", review_case), ["support"],
[ReadPerm("support_cases")]),
Open the complete repaired source.
The same check, with the repaired source and no changed assumptions, returns
proven: true and marks support_cases holds.
Exact repaired request · complete captured response
Tool report — recorded:
{
"binding": "load_for_staff",
"resource": "support_cases",
"operation": "db_read_opt",
"kind": "RoleAuthorityProven",
"status": "holds",
"detail": "every route reaching this binding requires every role (support)"
}
Author’s interpretation: the compiled route graph now gives
the helper the declared role authority. The customer read remains guarded and
the customer write remains dominated by owns_case.
On the same repaired component, api_permissions compared each
route’s declared operations with the CRUD effects inferred from compiled IR;
all five routes are recorded as match.
Exact permissions request
· captured response
Run, edit, repair, and reset
Open the drawer. Run function executes the compiled customer
handler as Alice against the displayed rows. Change p.user_id to
mallory to exercise the denial. Check access runs
the static checker. Switch between both complete versions, edit a copy, and use
Reset example to restore the recording source.
Code & run Customer support access before and after
Ask a connected agent to make the repair
Open Work with your agent inside the drawer, connect this tab through WebMCP, and send:
Call yichus_example_read for exampleId "support_access". Preserve the requirements and GuardedOrRoles policy. Run the current customer handler for Alice and Mallory, then run the access check. Repair the route-authority finding without removing the convenience route or weakening the policy. Use revision-aware updates, rerun both behaviors and the access check, and read yichus_example_feedback before reporting what changed.
The page tools reject stale revisions and return the visible result after an edit. The agent is editing this browser example, not silently changing a repository checkout.
Recorded behavior checks
These are direct executions of compiled handlers in a fresh seeded in-memory
world. Alice and Mallory are browser test inputs. The staff run calls
review_case directly, so it bypasses route dispatch and does not
demonstrate HTTP authentication or role enforcement.
| Run | Recorded response | Evidence |
|---|---|---|
| Alice views her case | 200 · public case fields, no staff note | response |
| Mallory views Alice’s case | 403 · no case fields | response |
| Direct staff review | 200 · includes the private note | response |
| Alice requests a missing case | 404 | response |
| Alice replies to her case | 200 · stored reply appears in the response | response |
| Mallory replies to Alice’s case | 403 · seeded row remains unchanged | response |
| Direct staff resolution | 200 · resolved with the new private note | response |
What changed, and what the result establishes
The static result establishes the declared GuardedOrRoles policy
for every supported operation in this compiled source: customer row uses sit
under owns_case, and every route reaching the unguarded staff
operations requires support. The recorded runs separately show the
intended responses for seven concrete inputs, including both write paths, a denied write, and a missing case.
The result assumes the server engine authenticates requests, supplies the
correct Principal, and enforces role_route before handler
invocation. It does not inspect a production identity provider, database, or
reverse proxy. It also does not decide whether the names owns_case
and support express the organization’s real-world policy.
The IO audit separately reports read-then-write patterns in
reply_to_case and resolve_case. The worked example does
not claim concurrent-update safety: two writers can overwrite each other unless
the deployed store serializes them. A production version should use the
transaction contract or an appropriate compare-and-set operation for those updates.
The access result neither proves nor weakens that separate concurrency requirement.
Recording provenance, source hashes, engine artifact hash, method, seed, and parameters · desktop capture · mobile capture · Access-check semantics and trusted boundaries
Where this fits
What this is about: Safety and Permissions