From a0028ab83fa13cb5c1e86e91b4f1d2db2e51c7c5 Mon Sep 17 00:00:00 2001 From: Jared Atkinson Date: Wed, 30 Sep 2026 09:37:12 -0700 Subject: [PATCH] Qualify GitHub environment node names by repository --- descriptions/nodes/GH_Environment.md | 4 ++-- src/openhound_github/models/environment.py | 2 +- src/openhound_github/models/workflow_job.py | 4 +++- tests/test_environment_model.py | 3 +++ tests/test_workflow_interception_path.py | 4 ++-- tests/test_workflow_model.py | 8 ++++---- 6 files changed, 15 insertions(+), 10 deletions(-) diff --git a/descriptions/nodes/GH_Environment.md b/descriptions/nodes/GH_Environment.md index d71f8e5..588f819 100644 --- a/descriptions/nodes/GH_Environment.md +++ b/descriptions/nodes/GH_Environment.md @@ -12,8 +12,8 @@ GH_CanRequestOIDCTokenFor edges from GH_WorkflowJob nodes identify jobs with a s | Property | Type | Description | | --- | --- | --- | -| `name` | `string` | The node name used for matching and display. | -| `displayname` | `string` | The human-readable display name. | +| `name` | `string` | The repository-qualified environment name (e.g., `org/repo/production`). | +| `displayname` | `string` | The environment name shown in the UI (e.g., `production`). | | `environmentid` | `string` | The identifier of the GitHub environment where this node was collected. | | `last_seen` | `datetime` | The timestamp when this node was last observed during collection. | | `node_id` | `string` | The stable identifier used as the OpenGraph node ID; this is the native GitHub node ID where available. | diff --git a/src/openhound_github/models/environment.py b/src/openhound_github/models/environment.py index 2c1fb9e..fd19d33 100644 --- a/src/openhound_github/models/environment.py +++ b/src/openhound_github/models/environment.py @@ -296,7 +296,7 @@ def as_node(self) -> GHNode: return GHNode( kinds=[nk.ENVIRONMENT], properties=GHEnvironmentProperties( - name=self.name, + name=f"{self.repository_full_name}/{self.name}", displayname=self.name, node_id=eid, short_name=self.name, diff --git a/src/openhound_github/models/workflow_job.py b/src/openhound_github/models/workflow_job.py index f7874fe..eb2c0d9 100644 --- a/src/openhound_github/models/workflow_job.py +++ b/src/openhound_github/models/workflow_job.py @@ -443,7 +443,9 @@ def _environment_edges(self): PropertyMatch( key="repository_id", value=self.repository_node_id ), - PropertyMatch(key="name", value=persisted_environment_name), + PropertyMatch( + key="short_name", value=persisted_environment_name + ), ], ), properties=EdgeProperties(traversable=False), diff --git a/tests/test_environment_model.py b/tests/test_environment_model.py index 79ad078..73affb8 100644 --- a/tests/test_environment_model.py +++ b/tests/test_environment_model.py @@ -141,6 +141,9 @@ def test_environment_node_surfaces_protection_rule_properties() -> None: node = env.as_node + assert node.properties.name == "github/hello-world/staging" + assert node.properties.displayname == "staging" + assert node.properties.short_name == "staging" assert node.properties.wait_timer == 30 assert node.properties.prevent_self_review is False assert node.properties.reviewer_count == 2 diff --git a/tests/test_workflow_interception_path.py b/tests/test_workflow_interception_path.py index 0e3fbde..507ab94 100644 --- a/tests/test_workflow_interception_path.py +++ b/tests/test_workflow_interception_path.py @@ -255,13 +255,13 @@ def test_cross_org_enterprise_runner_interception_path_is_traversable() -> None: matcher.key: matcher.value for matcher in can_request_oidc_token.end.property_matchers } == { - "name": "prod", + "short_name": "prod", "repository_id": "REPO_B", } assert { matcher.key: matcher.value for matcher in deploys_to.end.property_matchers } == { - "name": "prod", + "short_name": "prod", "repository_id": "REPO_B", } diff --git a/tests/test_workflow_model.py b/tests/test_workflow_model.py index d7282ce..788f3ed 100644 --- a/tests/test_workflow_model.py +++ b/tests/test_workflow_model.py @@ -527,7 +527,7 @@ def test_workflow_job_emits_can_request_oidc_token_for_environment_without_oidc_ assert len(environment_edges) == 1 assert _matcher_values(environment_edges[0]) == { "repository_id": "REPO_1", - "name": "prod", + "short_name": "prod", } assert len(edges) == 1 assert edges[0].kind == ek.CAN_REQUEST_OIDC_TOKEN_FOR @@ -535,7 +535,7 @@ def test_workflow_job_emits_can_request_oidc_token_for_environment_without_oidc_ assert edges[0].end.kind == nk.ENVIRONMENT assert _matcher_values(edges[0]) == { "repository_id": "REPO_1", - "name": "prod", + "short_name": "prod", } assert edges[0].properties.traversable is True assert edges[0].properties.composed is True @@ -627,8 +627,8 @@ def test_workflow_job_can_request_oidc_token_for_edges_are_per_job_and_idempoten ] assert [(edge.start.value, _matcher_values(edge)) for edge in edges] == [ - ("JOB_1", {"repository_id": "REPO_1", "name": "prod"}), - ("JOB_2", {"repository_id": "REPO_1", "name": "prod"}), + ("JOB_1", {"repository_id": "REPO_1", "short_name": "prod"}), + ("JOB_2", {"repository_id": "REPO_1", "short_name": "prod"}), ] assert len(list(jobs[0]._can_request_oidc_token_for_edges)) == 1