dendrite
strata query compiler
github
google-drive
photoflash
compile
⌘↵
strata
-- ═══════════════════════════════════════════════════════════════════════════ -- GitHub-like repository authorization model -- ═══════════════════════════════════════════════════════════════════════════ -- -- Organizations own repositories. Users access repos through: -- 1. Direct collaboration (invited to a repo) -- 2. Team membership (team has repo access) -- 3. Organization ownership (org owner sees everything) -- -- Role hierarchy: owner > admin > maintain > write > read -- Teams can be nested. Permissions flow down through team hierarchy. FROM "runtime" NODE session END FROM "postgres" -- ── Users & Identity ──────────────────────────────────────────────────── NODE users ACCEPT "authenticated" NODE emails ACCEPT "select" SURFACE id, address, verified, primary -- ── Organizations ─────────────────────────────────────────────────────── NODE orgs ACCEPT "owner" SURFACE id, name, billing_email ACCEPT "member" SURFACE id, name NODE org_memberships NODE org_invitations -- ── Teams ─────────────────────────────────────────────────────────────── NODE teams ACCEPT "maintainer" SURFACE id, name, slug, description, privacy ACCEPT "member" SURFACE id, name, slug NODE team_memberships NODE parent_teams -- ── Repositories ──────────────────────────────────────────────────────── NODE repos ACCEPT "admin" SURFACE id, name, full_name, private, description, default_branch ACCEPT "maintain" SURFACE id, name, full_name, private, description, default_branch ACCEPT "write" SURFACE id, name, full_name, private, description ACCEPT "read" SURFACE id, name, full_name NODE repo_collaborators NODE team_repos -- ── Issues & Pull Requests ────────────────────────────────────────────── NODE issues ACCEPT "write" SURFACE id, title, body, state, number, created_at ACCEPT "read" SURFACE id, title, state, number, created_at NODE pull_requests ACCEPT "write" SURFACE id, title, body, state, number, head_ref, base_ref, created_at ACCEPT "read" SURFACE id, title, state, number, created_at NODE comments ACCEPT "write" SURFACE id, body, author_id, created_at ACCEPT "read" SURFACE id, body, created_at -- ── Branches & Protection ────────────────────────────────────────────── NODE branches ACCEPT "admin" SURFACE id, name, protected ACCEPT "read" SURFACE id, name, protected NODE branch_protections ACCEPT "admin" SURFACE id, pattern, required_reviews, dismiss_stale_reviews -- ── Edges ─────────────────────────────────────────────────────────────── -- Identity EDGE is_user (s:session)-[]->(u:users) ON u.id = s.user_id EDGE user_email (u:users)-[]->(e:emails) ON e.user_id = u.id -- Org membership EDGE org_member (u:users)-[]->(m:org_memberships)-[]->(o:orgs) ON m.user_id = u.id AND o.id = m.org_id EDGE org_invite (o:orgs)-[]->(inv:org_invitations) ON inv.org_id = o.id -- Team structure EDGE org_team (o:orgs)-[]->(t:teams) ON t.org_id = o.id EDGE team_member (u:users)-[]->(tm:team_memberships)-[]->(t:teams) ON tm.user_id = u.id AND t.id = tm.team_id EDGE nested_team (parent:teams)-[]->(link:parent_teams)-[]->(child:teams) ON link.parent_id = parent.id AND child.id = link.child_id -- Repository access EDGE org_repo (o:orgs)-[]->(r:repos) ON r.org_id = o.id EDGE collaborator (u:users)-[]->(rc:repo_collaborators)-[]->(r:repos) ON rc.user_id = u.id AND r.id = rc.repo_id EDGE team_repo_access (t:teams)-[]->(tr:team_repos)-[]->(r:repos) ON tr.team_id = t.id AND r.id = tr.repo_id -- Repo contents EDGE repo_issue (r:repos)-[]->(i:issues) ON i.repo_id = r.id EDGE repo_pr (r:repos)-[]->(pr:pull_requests) ON pr.repo_id = r.id EDGE issue_comment (i:issues)-[]->(c:comments) ON c.commentable_id = i.id EDGE pr_comment (pr:pull_requests)-[]->(c:comments) ON c.commentable_id = pr.id EDGE repo_branch (r:repos)-[]->(b:branches) ON b.repo_id = r.id EDGE branch_protection (b:branches)-[]->(bp:branch_protections) ON bp.branch_id = b.id END -- ═══════════════════════════════════════════════════════════════════════════ -- Paths -- ═══════════════════════════════════════════════════════════════════════════ -- Principal closure: session → user PATH acts_as (s:session)-[]->(u:users) WALK (s:session)-[:is_user]->(u:users) -- ═══════════════════════════════════════════════════════════════════════════ -- Rules -- ═══════════════════════════════════════════════════════════════════════════ -- Session → User RULE authenticate WALK (s:session)-[:acts_as]->(u:users) CONVEYS "authenticated" TO u -- User → Emails RULE user_emails WALK (u:users)-[:user_email]->(e:emails) PROPAGATES "authenticated" AS "select" IMPLICITLY -- ── Organization access ────────────────────────────────────────────────── -- User → Org (through membership, carries role from membership table) RULE org_membership WALK (u:users)-[:org_member]->(o:orgs) WALK (u)-[:org_member]->(m:org_memberships) PROPAGATES m.role TO o IMPLICITLY -- Org owner → all org repos with admin RULE org_owner_repos WALK (o:orgs)-[:org_repo]->(r:repos) PROPAGATES "owner" AS "admin" IMPLICITLY PROPAGATES "owner" AS "read" IMPLICITLY PROPAGATES "member" AS "read" IMPLICITLY -- ── Team access ────────────────────────────────────────────────────────── -- Org → Teams RULE org_teams WALK (o:orgs)-[:org_team]->(t:teams) PROPAGATES "owner" AS "maintainer" IMPLICITLY PROPAGATES "member" AS "member" IMPLICITLY -- User → Team (through membership) RULE team_membership WALK (u:users)-[:team_member]->(t:teams) PROPAGATES "authenticated" AS "member" IMPLICITLY -- Nested teams: parent team permissions flow to child -- No IMPLICITLY — explicit query only, prevents recursive unrolling RULE nested_team_access WALK (parent:teams)-[:nested_team]->(child:teams) PROPAGATES "maintainer" PROPAGATES "member" -- Team → Repo (through team_repos, carries permission from junction) RULE team_repo WALK (t:teams)-[:team_repo_access]->(r:repos) WALK (t)-[:team_repo_access]->(tr:team_repos) PROPAGATES tr.permission TO r IMPLICITLY -- ── Direct collaboration ───────────────────────────────────────────────── -- User → Repo (through collaborator invite, carries permission) RULE direct_collaborator WALK (u:users)-[:collaborator]->(r:repos) WALK (u)-[:collaborator]->(rc:repo_collaborators) PROPAGATES rc.permission TO r IMPLICITLY -- ── Repository contents ────────────────────────────────────────────────── -- Repo → Issues RULE repo_issues WALK (r:repos)-[:repo_issue]->(i:issues) PROPAGATES "admin" AS "write" IMPLICITLY PROPAGATES "maintain" AS "write" IMPLICITLY PROPAGATES "write" AS "write" IMPLICITLY PROPAGATES "read" AS "read" IMPLICITLY -- Repo → Pull Requests RULE repo_pull_requests WALK (r:repos)-[:repo_pr]->(pr:pull_requests) PROPAGATES "admin" AS "write" IMPLICITLY PROPAGATES "maintain" AS "write" IMPLICITLY PROPAGATES "write" AS "write" IMPLICITLY PROPAGATES "read" AS "read" IMPLICITLY -- Issue/PR → Comments RULE issue_comments WALK (i:issues)-[:issue_comment]->(c:comments) PROPAGATES "write" IMPLICITLY PROPAGATES "read" IMPLICITLY RULE pr_comments WALK (pr:pull_requests)-[:pr_comment]->(c:comments) PROPAGATES "write" IMPLICITLY PROPAGATES "read" IMPLICITLY -- Repo → Branches RULE repo_branches WALK (r:repos)-[:repo_branch]->(b:branches) PROPAGATES "admin" IMPLICITLY PROPAGATES "maintain" AS "read" IMPLICITLY PROPAGATES "write" AS "read" IMPLICITLY PROPAGATES "read" IMPLICITLY -- Branch → Protection (admin only) RULE branch_protection_rules WALK (b:branches)-[:branch_protection]->(bp:branch_protections) PROPAGATES "admin" IMPLICITLY -- ═══════════════════════════════════════════════════════════════════════════ -- Operations (FUNCs) -- ═══════════════════════════════════════════════════════════════════════════ -- Repo-scoped (requires write) FUNC create_issue(repo:repos, title, body) AS create_issue REQUIRES "write" ON repo FUNC create_pull_request(repo:repos, title, body, head_ref, base_ref) AS create_pr REQUIRES "write" ON repo -- Issue-scoped (requires write) FUNC add_comment(issue:issues, body) AS comment_on_issue REQUIRES "write" ON issue FUNC close_issue(issue:issues) AS close_issue REQUIRES "write" ON issue -- Repo-scoped (requires admin) FUNC add_collaborator(repo:repos, user_id, permission) AS add_collaborator REQUIRES "admin" ON repo -- Branch-scoped (requires admin — flows from repo admin through branches) FUNC set_branch_protection(branch:branches, pattern, required_reviews) AS protect_branch REQUIRES "admin" ON branch -- Org-scoped (requires owner) FUNC create_team(org:orgs, name) AS create_team REQUIRES "owner" ON org
cypher
query
MATCH (r:repos)-[:repo_issue]->(i:issues)-[:issue_comment]->(c:comments) RETURN r, i, c
Ctrl+Enter to compile
sql
compile to see SQL