Skip to content

Commit e58e1a7

Browse files
committed
Add composite edge (can_read_secret) to org_secret resource
1 parent d854ea8 commit e58e1a7

1 file changed

Lines changed: 65 additions & 5 deletions

File tree

src/openhound_github/models/org_secret.py

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from openhound.core.asset import BaseAsset, EdgeDef, NodeDef
77
from openhound.core.models.entries_dataclass import Edge, EdgePath, EdgeProperties
88

9-
from openhound_github.graph import GHNode, GHNodeProperties
9+
from openhound_github.graph import GHEdgeProperties, GHNode, GHNodeProperties
1010
from openhound_github.kinds import edges as ek
1111
from openhound_github.kinds import nodes as nk
1212
from openhound_github.main import app
@@ -15,7 +15,7 @@
1515
@dataclass
1616
class GHOrgSecretProperties(GHNodeProperties):
1717
"""Org secret properties and accordion panel queries.
18-
18+
1919
Attributes:
2020
visibility: The secret's visibility scope: `all` (all repos), `private` (private and internal repos), or `selected` (specific repos).
2121
environment_name: The name of the environment (GitHub organization).
@@ -55,6 +55,13 @@ class GHOrgSecretProperties(GHNodeProperties):
5555
description="Repository can access org secret",
5656
traversable=True,
5757
),
58+
EdgeDef(
59+
start=nk.ORG_ROLE,
60+
end=nk.ORG_SECRET,
61+
kind=ek.CAN_READ_SECRET,
62+
description="Org role can read org secret by creating a repository in scope",
63+
traversable=True,
64+
),
5865
],
5966
)
6067
class OrgSecret(BaseAsset):
@@ -96,6 +103,15 @@ def as_node(self) -> GHNode:
96103
),
97104
)
98105

106+
def _read_secret_query(self, role_node_id: str) -> str:
107+
return (
108+
f"MATCH p=(:GH_OrgRole {{node_id:'{role_node_id}'}})"
109+
f"-[:GH_CanCreateRepositories|GH_CanCreatePublicRepositories|"
110+
f"GH_CanCreateInternalRepositories|GH_CanCreatePrivateRepositories]->"
111+
f"(:GH_Organization)-[:GH_Contains]->"
112+
f"(:GH_OrgSecret {{node_id:'{self.node_id}'}}) RETURN p"
113+
)
114+
99115
@property
100116
def _all_repo_edges(self):
101117
if self.visibility == "all":
@@ -111,7 +127,9 @@ def _all_repo_edges(self):
111127
@property
112128
def _private_repo_edges(self):
113129
if self.visibility == "private":
114-
for repo in self._lookup.private_repository_node_ids_for_org(self.org_login):
130+
for repo in self._lookup.private_repository_node_ids_for_org(
131+
self.org_login
132+
):
115133
for repo_node_id in repo:
116134
yield Edge(
117135
kind=ek.HAS_SECRET,
@@ -121,15 +139,50 @@ def _private_repo_edges(self):
121139
)
122140

123141
@property
124-
def edges(self):
142+
def _contains_edge(self):
125143
yield Edge(
126144
kind=ek.CONTAINS,
127145
start=EdgePath(value=self.org_node_id, match_by="id"),
128146
end=EdgePath(value=self.node_id, match_by="id"),
129147
properties=EdgeProperties(traversable=False),
130148
)
149+
150+
@property
151+
def _composed_read_secret_edges(self):
152+
if self.visibility != "all":
153+
return
154+
155+
owners_role_id = f"{self.org_node_id}_owners"
156+
yield Edge(
157+
kind=ek.CAN_READ_SECRET,
158+
start=EdgePath(value=owners_role_id, match_by="id"),
159+
end=EdgePath(value=self.node_id, match_by="id"),
160+
properties=GHEdgeProperties(
161+
traversable=True,
162+
composed=True,
163+
query_composition=self._read_secret_query(owners_role_id),
164+
),
165+
)
166+
167+
if self._lookup.members_can_create_repository(self.org_login):
168+
members_role_id = f"{self.org_node_id}_members"
169+
yield Edge(
170+
kind=ek.CAN_READ_SECRET,
171+
start=EdgePath(value=members_role_id, match_by="id"),
172+
end=EdgePath(value=self.node_id, match_by="id"),
173+
properties=GHEdgeProperties(
174+
traversable=True,
175+
composed=True,
176+
query_composition=self._read_secret_query(members_role_id),
177+
),
178+
)
179+
180+
@property
181+
def edges(self):
182+
yield from self._contains_edge
131183
yield from self._all_repo_edges
132184
yield from self._private_repo_edges
185+
yield from self._composed_read_secret_edges
133186

134187

135188
@app.asset(
@@ -164,17 +217,24 @@ def as_node(self) -> None:
164217
return None
165218

166219
@property
167-
def edges(self):
220+
def _contains_edge(self):
168221
yield Edge(
169222
kind=ek.CONTAINS,
170223
start=EdgePath(value=self.org_node_id, match_by="id"),
171224
end=EdgePath(value=self.node_id, match_by="id"),
172225
properties=EdgeProperties(traversable=False),
173226
)
174227

228+
@property
229+
def _has_secret_edge(self):
175230
yield Edge(
176231
kind=ek.HAS_SECRET,
177232
start=EdgePath(value=self.repository_node_id, match_by="id"),
178233
end=EdgePath(value=self.node_id, match_by="id"),
179234
properties=EdgeProperties(traversable=True),
180235
)
236+
237+
@property
238+
def edges(self):
239+
yield from self._contains_edge
240+
yield from self._has_secret_edge

0 commit comments

Comments
 (0)