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 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ The collector runs successfully with the documented read-only permission set. So

- Organization `Members: write` enables external group mapping collection for IdP-synced teams, which allows the converter to emit `SCIM_Provisioned` edges from `SCIM_Group` to `GH_Team`. This is useful when the organization uses team synchronization with an external identity provider; if no GitHub teams are linked to external groups, this permission does not add graph data.
- Classic PAT scope `manage_runners:enterprise` enables enterprise self-hosted runner group and runner collection. This is useful when the enterprise has enterprise-scoped runner groups or runners, especially runner groups shared into organizations; if all runners are organization- or repository-scoped, this scope does not add graph data.
- Repository `Administration: read` enables deploy key collection. GitHub exposes repository deploy keys through an administration-scoped read endpoint, and the collector emits `GH_DeployKey` nodes only when that endpoint is accessible.

If these optional permissions are not granted, OpenHound skips the affected resources and continues collecting the rest of the GitHub environment.

Expand Down
20 changes: 20 additions & 0 deletions descriptions/edges/GH_AddedDeployKey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# GH_AddedDeployKey

## General Information

User added this repository deploy key.

## Edge Schema

| Source | Destination | Traversable |
| --- | --- | --- |
| `GH_User` | `GH_DeployKey` | `false` |

## Diagram

```mermaid
graph LR
n0["GH_User"]
n1["GH_DeployKey"]
n0 -.->|GH_AddedDeployKey| n1
```
11 changes: 7 additions & 4 deletions descriptions/edges/GH_CanAccess.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

## General Information

The non-traversable GH_CanAccess edge indicates that a personal access token or app installation has been granted access to specific repositories. This edge represents the scope of access granted to a token or app rather than a direct attack path, providing visibility into which repositories are reachable through non-human credentials. It is non-traversable because token and app access does not transitively extend to other principals.
The non-traversable GH_CanAccess edge indicates that a personal access token, app installation, or deploy key has been granted access to a repository or organization. This edge represents the scope of access granted to a non-human credential rather than a direct attack path, providing visibility into which repositories are reachable through that credential. It is non-traversable because credential access does not transitively extend to other principals.

## Edge Schema

| Source | Destination | Traversable |
| --- | --- | --- |
| `GH_AppInstallation` | `GH_Repository` | `false` |
| `GH_DeployKey` | `GH_Repository` | `false` |
| `GH_PersonalAccessToken` | `GH_Organization` | `false` |
| `GH_PersonalAccessToken` | `GH_Repository` | `false` |

Expand All @@ -18,9 +19,11 @@ The non-traversable GH_CanAccess edge indicates that a personal access token or
graph LR
n0["GH_AppInstallation"]
n1["GH_Repository"]
n2["GH_PersonalAccessToken"]
n3["GH_Organization"]
n2["GH_DeployKey"]
n3["GH_PersonalAccessToken"]
n4["GH_Organization"]
n0 -.->|GH_CanAccess| n1
n2 -.->|GH_CanAccess| n3
n2 -.->|GH_CanAccess| n1
n3 -.->|GH_CanAccess| n4
n3 -.->|GH_CanAccess| n1
```
24 changes: 24 additions & 0 deletions descriptions/edges/GH_CanRequestOIDCTokenFor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# GH_CanRequestOIDCTokenFor

## General Information

The traversable GH_CanRequestOIDCTokenFor edge represents that a GitHub Actions workflow job execution context can request a GitHub-signed OIDC token containing claims for its associated GitHub Environment.

This edge is derived from the existing GH_DeploysTo relationship and the job's calculated `effective_github_token_permissions`. The collector emits it only when the job targets a statically resolved environment and its effective permissions include `id-token:write`.

This is a capability edge, not evidence that the workflow has historically requested a token or contains an explicit OIDC-related step. Code executing in a job with `id-token:write` can request the token directly.

## Edge Schema

| Source | Destination | Traversable |
| --- | --- | --- |
| `GH_WorkflowJob` | `GH_Environment` | `true` |

## Diagram

```mermaid
graph LR
n0["GH_WorkflowJob"]
n1["GH_Environment"]
n0 -->|GH_CanRequestOIDCTokenFor| n1
```
21 changes: 12 additions & 9 deletions descriptions/edges/GH_Contains.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ The non-traversable GH_Contains edge represents structural containment within th
| `GH_Organization` | `GH_SecretScanningAlert` | `false` |
| `GH_Repository` | `GH_Branch` | `false` |
| `GH_Repository` | `GH_BranchProtectionRule` | `false` |
| `GH_Repository` | `GH_DeployKey` | `false` |
| `GH_Repository` | `GH_Environment` | `false` |
| `GH_Repository` | `GH_RepoRunner` | `false` |
| `GH_Repository` | `GH_RepoSecret` | `false` |
Expand Down Expand Up @@ -62,12 +63,13 @@ graph LR
n19["GH_Repository"]
n20["GH_Branch"]
n21["GH_BranchProtectionRule"]
n22["GH_RepoRunner"]
n23["GH_RepoSecret"]
n24["GH_RepoVariable"]
n25["GH_Workflow"]
n26["GH_WorkflowJob"]
n27["GH_WorkflowStep"]
n22["GH_DeployKey"]
n23["GH_RepoRunner"]
n24["GH_RepoSecret"]
n25["GH_RepoVariable"]
n26["GH_Workflow"]
n27["GH_WorkflowJob"]
n28["GH_WorkflowStep"]
n0 -.->|GH_Contains| n1
n0 -.->|GH_Contains| n2
n0 -.->|GH_Contains| n3
Expand All @@ -87,12 +89,13 @@ graph LR
n4 -.->|GH_Contains| n18
n19 -.->|GH_Contains| n20
n19 -.->|GH_Contains| n21
n19 -.->|GH_Contains| n6
n19 -.->|GH_Contains| n22
n19 -.->|GH_Contains| n6
n19 -.->|GH_Contains| n23
n19 -.->|GH_Contains| n24
n19 -.->|GH_Contains| n18
n19 -.->|GH_Contains| n25
n25 -.->|GH_Contains| n26
n19 -.->|GH_Contains| n18
n19 -.->|GH_Contains| n26
n26 -.->|GH_Contains| n27
n27 -.->|GH_Contains| n28
```
6 changes: 4 additions & 2 deletions descriptions/nodes/GH_AppInstallation.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

## General Information

Represents a GitHub App installed on an organization. App installations have specific permissions and can be scoped to all repositories or a selection of repositories. The permissions granted to the app are captured as a JSON string in the properties.
Represents a GitHub App installed on an organization. App installations have specific permissions and can be scoped to all repositories or a selection of repositories. The permissions granted to the installation are stored as `scope:access` values such as `contents:write` in the `permissions` property.

Unlike fine-grained personal access tokens, GitHub does not expose separate organization and repository permission buckets for app installations, so this property remains a single flat permission list.

Each installation is linked to its parent GH_App via a GH_InstalledAs edge. For installations with `repository_selection` set to `all`, GH_CanAccess edges are created to every repository in the organization. For installations with `repository_selection` set to `selected`, repository-level edges cannot be enumerated with a PAT (requires app installation token authentication).

Expand All @@ -24,7 +26,7 @@ Each installation is linked to its parent GH_App via a GH_InstalledAs edge. For
| `repositories_url` | `string` | API URL to list repositories accessible to this installation. |
| `repository_selection` | `string` | Whether the app has access to `all` repositories or `selected` repositories. |
| `target_type` | `string` | The target type of the installation (e.g., `Organization`). |
| `permissions` | `string` | JSON string of the permissions granted to the app (e.g., `{"contents": "read", "metadata": "read"}`). |
| `permissions` | `list[string]` | Permissions granted to the installation in `scope:access` form. |
| `events` | `string` | JSON string of the webhook events the app subscribes to. |
| `created_at` | `datetime` | When the app was installed. |
| `updated_at` | `datetime` | When the installation was last updated. |
Expand Down
43 changes: 43 additions & 0 deletions descriptions/nodes/GH_DeployKey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# GH_DeployKey

## General Information

A repository-scoped SSH deploy key that grants read-only or read-write access to repository contents.

## Properties

| Property | Type | Description |
| --- | --- | --- |
| `name` | `string` | The node name used for matching and display. |
| `displayname` | `string` | The human-readable display name. |
| `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. |
| `github_id` | `integer` | The numeric GitHub deploy key ID. |
| `title` | `string` | The user-assigned deploy key title. |
| `key` | `string` | The public SSH key material. |
| `verified` | `boolean` | Whether GitHub has verified the deploy key. |
| `enabled` | `boolean` | Whether the deploy key is currently enabled. |
| `read_only` | `boolean` | Whether the deploy key is restricted to read-only repository access. |
| `repository_permissions` | `list[string]` | Repository-scoped permissions in `scope:access` form. |
| `created_at` | `string` | When the deploy key was created. |
| `last_used` | `string` | When the deploy key was last used. |
| `added_by_login` | `string` | The login of the user who added the deploy key. |
| `added_by_id` | `string` | The node ID of the user who added the deploy key. |
| `repository_name` | `string` | The full name of the containing repository. |
| `repository_id` | `string` | The node_id of the containing repository. |
| `environment_name` | `string` | The name of the environment (GitHub organization). |
| `query_repository` | `string` | Query for the containing repository. |
| `query_added_by` | `string` | Query for the user who added the deploy key. |

## Diagram

```mermaid
graph LR
n0["GH_DeployKey"]
n1["GH_Repository"]
n2["GH_User"]
n0 -.->|GH_CanAccess| n1
n1 -.->|GH_Contains| n0
n2 -.->|GH_AddedDeployKey| n0
```
3 changes: 2 additions & 1 deletion descriptions/nodes/GH_Enterprise.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ A GitHub Enterprise account that contains organizations, enterprise teams, roles
| `created_at` | `string` | When the enterprise was created. |
| `updated_at` | `string` | When the enterprise was last updated. |
| `billing_email` | `string` | The enterprise billing email. |
| `security_contact_email` | `string` | The enterprise security contact email. |
| `viewer_is_admin` | `boolean` | Whether the authenticated viewer is an enterprise admin. |
| `github_deployment_type` | `string` | The GitHub deployment type, such as `ghec` or `ghes`. |
| `ghes_version` | `string` | The GitHub Enterprise Server version, when applicable. |
| `environment_name` | `string` | The enterprise environment name. |
| `query_organizations` | `string` | Query for contained organizations. |

Expand Down
3 changes: 0 additions & 3 deletions descriptions/nodes/GH_EnterpriseRunner.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ When the runner is not explicitly marked ephemeral, GH_CanInterceptJob edges ide
graph LR
n0["GH_EnterpriseRunnerGroup"]
n1["GH_EnterpriseRunner"]
n2["GH_WorkflowJob"]
n0 -.->|GH_Contains| n1
n0 -->|GH_HasRunner| n1
n2 -.->|GH_RunsOn| n1
n1 -->|GH_CanInterceptJob| n2
```
3 changes: 3 additions & 0 deletions descriptions/nodes/GH_Environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Represents a GitHub Actions deployment environment configured on a repository. E

Repositories always contain their environments. When custom branch policies are configured, the environment also contains one or more GH_EnvironmentBranchPolicy nodes that describe which branches are allowed to deploy. Environment-scoped secrets and variables are modeled as child nodes of the environment and become available to workflow jobs that reference it.

GH_CanRequestOIDCTokenFor edges from GH_WorkflowJob nodes identify jobs whose execution context can request a GitHub-signed OIDC token for this environment because their effective `GITHUB_TOKEN` permissions include `id-token:write`.

## Properties

| Property | Type | Description |
Expand Down Expand Up @@ -56,5 +58,6 @@ graph LR
n7 -->|GH_CanDeployToEnvironment| n1
n8 -.->|GH_ApprovesDeploymentTo| n1
n8 -->|GH_CanDeployToEnvironment| n1
n9 -->|GH_CanRequestOIDCTokenFor| n1
n9 -.->|GH_DeploysTo| n1
```
1 change: 1 addition & 0 deletions descriptions/nodes/GH_EnvironmentSecret.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ graph LR
n3["GH_WorkflowStep"]
n0 -.->|GH_Contains| n1
n0 -->|GH_HasSecret| n1
n2 -->|GH_CanAccessSecret| n1
n2 -.->|GH_UsesSecret| n1
n3 -.->|GH_UsesSecret| n1
```
3 changes: 0 additions & 3 deletions descriptions/nodes/GH_OrgRunner.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ When the runner is not explicitly marked ephemeral, GH_CanInterceptJob edges ide
graph LR
n0["GH_OrgRunnerGroup"]
n1["GH_OrgRunner"]
n2["GH_WorkflowJob"]
n0 -.->|GH_Contains| n1
n0 -->|GH_HasRunner| n1
n2 -.->|GH_RunsOn| n1
n1 -->|GH_CanInterceptJob| n2
```
1 change: 1 addition & 0 deletions descriptions/nodes/GH_OrgSecret.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ graph LR
n0 -->|GH_CanReadSecret| n1
n2 -.->|GH_Contains| n1
n3 -->|GH_HasSecret| n1
n4 -->|GH_CanAccessSecret| n1
n4 -.->|GH_UsesSecret| n1
n5 -.->|GH_UsesSecret| n1
```
2 changes: 2 additions & 0 deletions descriptions/nodes/GH_Organization.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ Represents a GitHub organization. This is the root node of the graph and serves
| `self_hosted_runners_enabled_repositories` | `string` | Which repositories may use self-hosted runners: `all`, `selected`, or `none`. |
| `default_workflow_permissions` | `string` | The default workflow permissions property. |
| `can_approve_pull_request_reviews` | `boolean` | The can approve pull request reviews property. |
| `github_deployment_type` | `string` | The GitHub deployment type, such as `ghec` or `ghes`. |
| `ghes_version` | `string` | The GitHub Enterprise Server version, when applicable. |
| `query_organization_roles` | `string` | Query for organization roles. |
| `query_users` | `string` | Query for users. |
| `query_teams` | `string` | Query for teams. |
Expand Down
8 changes: 5 additions & 3 deletions descriptions/nodes/GH_PersonalAccessToken.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

## General Information

Represents a fine-grained personal access token that has been granted access to organization resources. PATs are linked to their owning user, the organization, and the repositories they can access. The permissions granted to the token are captured as a JSON string in the properties.
Represents a fine-grained personal access token that has been granted access to organization resources. PATs are linked to their owning user, the organization, and the repositories they can access.

The granted permissions are stored separately as `organization_permissions` and `repository_permissions`. Each property is a list of `scope:access` values such as `members:read` or `contents:write`, matching the permission format used on GH_WorkflowJob nodes.

## Properties

Expand All @@ -19,8 +21,8 @@ Represents a fine-grained personal access token that has been granted access to
| `token_expires_at` | `datetime` | The ISO 8601 timestamp of when the token expires. |
| `token_last_used_at` | `datetime` | The ISO 8601 timestamp of when the token was last used. |
| `access_granted_at` | `datetime` | The ISO 8601 timestamp of when the token was granted to the organization. |. |
| `organization_permissions` | `string` | JSON string of the PAT's organization-scoped permissions. |
| `repository_permissions` | `string` | JSON string of the PAT's repository-scoped permissions. |
| `organization_permissions` | `list[string]` | Organization-scoped permissions in `scope:access` form. |
| `repository_permissions` | `list[string]` | Repository-scoped permissions in `scope:access` form. |
| `token_name` | `string` | The user-assigned display name of the token. |
| `owner_login` | `string` | The login handle of the user who owns the token. |
| `repository_selection` | `string` | Whether the token has access to `all`, `subset`, or `none` of the organization's repositories. |
Expand Down
6 changes: 5 additions & 1 deletion descriptions/nodes/GH_PersonalAccessTokenRequest.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

## General Information

Represents a pending request from an organization member to access organization resources with a fine-grained personal access token. PAT requests are linked to their owning user and the organization. The requested permissions are captured as a JSON string in the properties.
Represents a pending request from an organization member to access organization resources with a fine-grained personal access token. PAT requests are linked to their owning user and the organization.

The requested permissions are stored separately as `organization_permissions` and `repository_permissions`. Each property is a list of `scope:access` values such as `members:read` or `contents:write`, matching the permission format used on GH_WorkflowJob nodes.

## Properties

Expand All @@ -18,6 +20,8 @@ Represents a pending request from an organization member to access organization
| `repository_selection` | `string` | Whether the request targets `all`, `subset`, or `none` of the organization's repositories. |
| `reason` | `string` | The rationale provided by the requester for the access request. |
| `org_name` | `string` | The org name property. |
| `organization_permissions` | `list[string]` | Requested organization-scoped permissions in `scope:access` form. |
| `repository_permissions` | `list[string]` | Requested repository-scoped permissions in `scope:access` form. |
| `query_organization_permissions` | `string` | Query for organization permissions. |
| `query_user` | `string` | Query for user. |
| `query_repositories` | `string` | Query for repositories. |
Expand Down
3 changes: 0 additions & 3 deletions descriptions/nodes/GH_RepoRunner.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ When the runner is not explicitly marked ephemeral, GH_CanInterceptJob edges ide
graph LR
n0["GH_Repository"]
n1["GH_RepoRunner"]
n2["GH_WorkflowJob"]
n0 -.->|GH_CanUseRunner| n1
n0 -.->|GH_Contains| n1
n2 -.->|GH_RunsOn| n1
n1 -->|GH_CanInterceptJob| n2
```
1 change: 1 addition & 0 deletions descriptions/nodes/GH_RepoSecret.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ graph LR
n3["GH_WorkflowStep"]
n0 -.->|GH_Contains| n1
n0 -->|GH_HasSecret| n1
n2 -->|GH_CanAccessSecret| n1
n2 -.->|GH_UsesSecret| n1
n3 -.->|GH_UsesSecret| n1
```
Loading
Loading