Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,592 changes: 1,561 additions & 31 deletions extension/schema.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ local_scheme = "no-local-version"

[dependency-groups]
dev = [
"openhound>=0.2.7",
"openhound>=0.4.0",
"pre-commit>=4.5.1",
"pytest>=9.0.1",
"ruff>=0.15.5",
Expand Down
10 changes: 10 additions & 0 deletions src/openhound_github/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
from openhound.core.models.entries_dataclass import Node as BaseNode
from openhound.core.models.entries_dataclass import NodeProperties as BaseProperties

GITHUB_SOURCE_KIND = "GitHub"
SAML_SOURCE_KIND = "SAML"


@dataclass
class GHNodeProperties(BaseProperties):
Expand All @@ -22,6 +25,13 @@ def __post_init__(self):
# Use GitHub's native node_id as the OpenGraph node id so edges can
# reference nodes by the same identifier used during collection.
self.id = self.properties.node_id
source_kind = (
SAML_SOURCE_KIND
if any(kind.startswith("SAML_") for kind in self.kinds)
else GITHUB_SOURCE_KIND
)
if source_kind not in self.kinds:
self.kinds.append(source_kind)


@dataclass
Expand Down
2 changes: 1 addition & 1 deletion src/openhound_github/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from .lookup import GithubLookup
from .transforms import transforms

app = OpenHound("github", source_kind="GitHub", help="OpenGraph collector for GitHub")
app = OpenHound("github", help="OpenGraph collector for GitHub")


@app.collect()
Expand Down
9 changes: 4 additions & 5 deletions src/openhound_github/models/scim_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
from openhound_github.main import app
from openhound_github.models.saml_helpers import detect_foreign_idp

SCIM_SOURCE_KIND = "SCIM"


def scim_organization_id(scope_node_id: str) -> str:
return f"SCIM_Organization_{scope_node_id}"
Expand All @@ -40,15 +42,15 @@ class ScimNodeProperties(NodeProperties):
profile_url: str | None = None
enterprise: str | None = None
organization: str | None = None
source_kind: str | None = None


@dataclass
class ScimNode(Node):
id: str

def __post_init__(self):
return None
if SCIM_SOURCE_KIND not in self.kinds:
self.kinds.append(SCIM_SOURCE_KIND)


class Name(BaseModel):
Expand Down Expand Up @@ -128,7 +130,6 @@ def as_node(self) -> ScimNode:
environmentid=self.scope_node_id,
enterprise=self.enterprise_slug,
organization=self.org_login,
source_kind="GitHub",
),
)

Expand Down Expand Up @@ -210,7 +211,6 @@ def as_node(self) -> ScimNode:
profile_url=self.meta.location if self.meta else None,
enterprise=self.enterprise_slug,
organization=self.org_login,
source_kind="GitHub",
),
)

Expand Down Expand Up @@ -306,7 +306,6 @@ def as_node(self) -> ScimNode:
external_id=self.external_id,
enterprise=self.enterprise_slug,
organization=self.org_login,
source_kind="GitHub",
),
)

Expand Down
14 changes: 9 additions & 5 deletions tests/test_runner_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ def test_org_runner_group_keeps_generic_runner_group_label() -> None:

node = group.as_node

assert node.kinds == [nk.ORG_RUNNER_GROUP, nk.RUNNER_GROUP]
assert node.kinds == [nk.ORG_RUNNER_GROUP, nk.RUNNER_GROUP, "GitHub"]
assert node.properties.scope == "organization"
assert node.id == "ORG_1_runner_group_1"

Expand Down Expand Up @@ -267,22 +267,26 @@ def test_runner_groups_and_runners_use_scope_owner_prefixes_with_generic_suffixe
)
repo_runner._lookup = SimpleNamespace(org_id_for_login=lambda _login: "ORG_1")

assert org_runner.as_node.kinds == [nk.ORG_RUNNER, nk.RUNNER]
assert org_runner.as_node.kinds == [nk.ORG_RUNNER, nk.RUNNER, "GitHub"]
assert org_runner.as_node.properties.scope == "organization"
assert org_runner.as_node.id == "ORG_1_runner_8"
assert org_runner.as_node.properties.name == "acme/org-runner-1"
assert org_runner.as_node.properties.displayname == "org-runner-1"
assert group.as_node.kinds == [nk.ENTERPRISE_RUNNER_GROUP, nk.RUNNER_GROUP]
assert group.as_node.kinds == [
nk.ENTERPRISE_RUNNER_GROUP,
nk.RUNNER_GROUP,
"GitHub",
]
assert group.as_node.properties.scope == "enterprise"
assert group.as_node.id == "ENT_1_runner_group_2"

assert runner.as_node.kinds == [nk.ENTERPRISE_RUNNER, nk.RUNNER]
assert runner.as_node.kinds == [nk.ENTERPRISE_RUNNER, nk.RUNNER, "GitHub"]
assert runner.as_node.properties.scope == "enterprise"
assert runner.as_node.id == "ENT_1_runner_9"
assert runner.as_node.properties.name == "acme-enterprise/enterprise-runner-1"
assert runner.as_node.properties.displayname == "enterprise-runner-1"

assert repo_runner.as_node.kinds == [nk.REPO_RUNNER, nk.RUNNER]
assert repo_runner.as_node.kinds == [nk.REPO_RUNNER, nk.RUNNER, "GitHub"]
assert repo_runner.as_node.properties.scope == "repository"
assert repo_runner.as_node.id == "REPO_1_runner_10"
assert repo_runner.as_node.properties.name == "acme/repo/repo-runner-1"
Expand Down
6 changes: 6 additions & 0 deletions tests/test_saml_models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from types import SimpleNamespace

from openhound_github.kinds import edges as ek
from openhound_github.kinds import nodes as nk
from openhound_github.graphql import ENTERPRISE_SAML_QUERY, SAML_IDENTITIES_QUERY
from openhound_github.models.external_identity import ExternalIdentity
from openhound_github.models.saml_assertion_consumer_service import (
Expand Down Expand Up @@ -58,6 +59,7 @@ def _saml_account_edge(identity: ExternalIdentity):
def test_external_identity_prefers_saml_username_for_display_name() -> None:
identity = _identity_with_lookup()

assert identity.as_node.kinds == [nk.EXTERNAL_IDENTITY, "GitHub"]
assert identity.as_node.properties.name == "Alice@example.com"
assert identity.as_node.properties.displayname == "Alice@example.com"

Expand Down Expand Up @@ -106,6 +108,9 @@ def test_normalized_saml_nodes_expose_contract_metadata() -> None:
assert service_provider.as_node.id == "github:saml:sp:org:acme"
assert issuer.as_node.id == "github:saml:trusted-issuer:org:acme"
assert acs.as_node.id == "github:saml:acs:org:acme"
assert service_provider.as_node.kinds == [nk.SAML_SERVICE_PROVIDER, "SAML"]
assert issuer.as_node.kinds == [nk.SAML_ISSUER, "SAML"]
assert acs.as_node.kinds == [nk.SAML_ASSERTION_CONSUMER_SERVICE, "SAML"]
assert sp_properties.github_deployment_id == DEFAULT_GITHUB_DEPLOYMENT_ID
assert sp_properties.github_web_origin == DEFAULT_GITHUB_WEB_ORIGIN
assert sp_properties.schema_contract_version == SAML_CONTRACT_VERSION
Expand Down Expand Up @@ -228,6 +233,7 @@ def test_saml_provider_replays_snake_case_fields_and_deployment_metadata() -> No
assert provider.sso_url == "https://issuer.example.com/sso"
assert provider.signature_method == "rsa-sha256"
assert provider.idp_certificate == "certificate-data"
assert provider.as_node.kinds == [nk.SAML_IDENTITY_PROVIDER, "GitHub"]
assert provider.as_node.properties.github_deployment_id == "github.example.com"
assert provider.as_node.properties.github_web_origin == "https://github.example.com"

Expand Down
5 changes: 3 additions & 2 deletions tests/test_scim_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def test_scim_user_emits_normalized_edges_without_legacy_correlation_by_default(
edges = list(user.edges)
unmatched_edges = list(unmatched_user.edges)

assert node.kinds == [nk.SCIM_USER]
assert node.kinds == [nk.SCIM_USER, "SCIM"]
assert node.properties.environmentid == "ENT_NODE_1"
assert node.properties.external_id == "00u-okta-1"
assert node.properties.name == "alice@example.test"
Expand Down Expand Up @@ -136,6 +136,7 @@ def test_scim_group_emits_membership_and_tenant_scoped_legacy_correlation() -> N

edges = list(group.edges)

assert group.as_node.kinds == [nk.SCIM_GROUP, "SCIM"]
assert [edge.kind for edge in edges] == [
ek.SCIM_CONTAINS,
ek.SCIM_MEMBER_OF,
Expand Down Expand Up @@ -180,7 +181,7 @@ def test_scim_organization_stays_within_github_environment_root() -> None:
node = organization.as_node

assert node.id == "SCIM_Organization_ENT_NODE_1"
assert node.kinds == [nk.SCIM_ORGANIZATION]
assert node.kinds == [nk.SCIM_ORGANIZATION, "SCIM"]
assert node.properties.environmentid == "ENT_NODE_1"


Expand Down
8 changes: 4 additions & 4 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading