imbi-plugin-github 2.18.0__tar.gz → 2.20.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. imbi_plugin_github-2.20.0/PKG-INFO +154 -0
  2. imbi_plugin_github-2.20.0/README.md +135 -0
  3. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/pyproject.toml +2 -2
  4. imbi_plugin_github-2.20.0/src/imbi/plugins/github/README.md +135 -0
  5. imbi_plugin_github-2.18.0/PKG-INFO +0 -126
  6. imbi_plugin_github-2.18.0/README.md +0 -107
  7. imbi_plugin_github-2.18.0/src/imbi/plugins/github/README.md +0 -107
  8. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/.gitignore +0 -0
  9. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/moon.yml +0 -0
  10. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/src/imbi/plugins/github/__init__.py +0 -0
  11. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/src/imbi/plugins/github/_app_auth.py +0 -0
  12. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/src/imbi/plugins/github/_hosts.py +0 -0
  13. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/src/imbi/plugins/github/_repos.py +0 -0
  14. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/src/imbi/plugins/github/commits.py +0 -0
  15. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/src/imbi/plugins/github/deployment.py +0 -0
  16. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/src/imbi/plugins/github/doctor.py +0 -0
  17. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/src/imbi/plugins/github/identity.py +0 -0
  18. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/src/imbi/plugins/github/lifecycle.py +0 -0
  19. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/src/imbi/plugins/github/plugin.py +0 -0
  20. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/src/imbi/plugins/github/pull_requests.py +0 -0
  21. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/src/imbi/plugins/github/py.typed +0 -0
  22. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/tests/__init__.py +0 -0
  23. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/tests/test_commits.py +0 -0
  24. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/tests/test_deployment.py +0 -0
  25. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/tests/test_doctor.py +0 -0
  26. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/tests/test_hosts.py +0 -0
  27. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/tests/test_identity.py +0 -0
  28. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/tests/test_lifecycle.py +0 -0
  29. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/tests/test_pull_requests.py +0 -0
  30. {imbi_plugin_github-2.18.0 → imbi_plugin_github-2.20.0}/tests/test_repos.py +0 -0
@@ -0,0 +1,154 @@
1
+ Metadata-Version: 2.4
2
+ Name: imbi-plugin-github
3
+ Version: 2.20.0
4
+ Summary: GitHub identity plugin for Imbi (github.com / GHEC / GHES)
5
+ Author-email: "Gavin M. Roy" <gavinr@aweber.com>
6
+ License-Expression: BSD-3-Clause
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Natural Language :: English
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Requires-Python: >=3.14
14
+ Requires-Dist: httpx>=0.27
15
+ Requires-Dist: imbi-common[databases]==2.20.0
16
+ Requires-Dist: pydantic>=2
17
+ Requires-Dist: pyjwt[crypto]>=2.8
18
+ Description-Content-Type: text/markdown
19
+
20
+ # imbi-plugin-github
21
+
22
+ GitHub plugin for Imbi. A single plugin — slug **`github`** — backs every
23
+ GitHub Integration; the integration-level `flavor` option selects
24
+ github.com (`github`), GitHub Enterprise Cloud (`ghec`), or GitHub
25
+ Enterprise Server (`ghes`), and `host` names the tenant or appliance.
26
+
27
+ ## Capabilities
28
+
29
+ | Kind | Handler |
30
+ | ----------------- | ------------------------- |
31
+ | `identity` | `GitHubIdentity` |
32
+ | `deployment` | `GitHubDeployment` |
33
+ | `lifecycle` | `GitHubLifecycle` |
34
+ | `webhook-actions` | `GitHubWebhookActions` |
35
+ | `commit-sync` | `GitHubCommitSync` |
36
+ | `pr-sync` | `GitHubPullRequestSync` |
37
+ | `analysis` | `GitHubDoctor` |
38
+
39
+ ### Identity
40
+
41
+ Implements the OAuth App flow. The access token returned by the OAuth
42
+ grant is passed straight to GitHub APIs as a `Bearer` token, so
43
+ `materialize()` is a no-op.
44
+
45
+ ### Deployment
46
+
47
+ Drives the GitHub Deployments API (`POST /repos/{owner}/{repo}/deployments`)
48
+ plus tag and release creation. Promote behaviour is inferred from the
49
+ ref shape by the host (semver → trigger Deployment, raw SHA → cut tag
50
+ + Release). Per-env workflow inputs ride on the `USES_PLUGIN` edge as
51
+ `env_payloads` and arrive on `PluginContext.environment_config`.
52
+
53
+ ### Lifecycle
54
+
55
+ Reacts to project archive / unarchive by archiving the matching repo via
56
+ `PATCH /repos/{owner}/{repo}` with `{"archived": true|false}`. When the
57
+ `archive_target_org` option is set, archive **also** transfers the repo to
58
+ that org first via `POST /repos/{owner}/{repo}/transfer` — useful for
59
+ moving sunset projects into a dedicated "archive" org so they no longer
60
+ crowd primary-org searches.
61
+
62
+ GitHub refuses to transfer archived repos, so an already-archived source
63
+ is briefly unarchived, transferred, and re-archived at the destination.
64
+ On unarchive the plugin only flips `archived` back to `false` at the
65
+ repo's current location — it does **not** transfer back to the original
66
+ org.
67
+
68
+ Archiving requires admin scope on the repo; transferring additionally
69
+ requires admin permission on the target organization.
70
+
71
+ ### Webhook actions (commit / tag / PR sync)
72
+
73
+ The `webhook-actions` capability exposes the actions the gateway
74
+ dispatches from webhook deliveries. A `WebhookRule.handler` is
75
+ `"<plugin_slug>#<action_name>"`, and the slug is the **plugin** slug —
76
+ `github` — not the capability kind:
77
+
78
+ | Action | Handler | Records into ClickHouse |
79
+ | --------------------- | ---------------------------- | ----------------------- |
80
+ | `sync_commits` | `github#sync_commits` | `commits` |
81
+ | `sync_tags` | `github#sync_tags` | `tags` |
82
+ | `sync_pull_requests` | `github#sync_pull_requests` | `pull_requests` |
83
+
84
+ `sync_commits` and `sync_tags` are dispatched from `push` deliveries;
85
+ `sync_pull_requests` from `pull_request` deliveries.
86
+
87
+ `sync_commits` fetches the full set of commits in a push via the compare
88
+ API (paginated, so it isn't capped by the 20-commit inline payload limit);
89
+ `sync_tags` records the pushed tag and, with `reconcile_all`, the repo's
90
+ full tag list. Branch/tag gating is the rule's CEL `filter_expression`,
91
+ which evaluates against the recorded event — the webhook body is under
92
+ `payload` (e.g. `payload.ref == "refs/heads/main"`,
93
+ `payload.ref.startsWith("refs/tags/")`). The API
94
+ flavor (github.com / GHEC / GHES) is resolved at runtime — explicit
95
+ `api_base_url`, else a connected GitHub plugin on the same service, else
96
+ the service endpoint, else the payload's `repository.url`.
97
+
98
+ Unlike identity/deployment/lifecycle (which act as the OAuth user),
99
+ commit-sync runs without an actor and authenticates with a **service**
100
+ credential in one of two modes, resolved per call:
101
+
102
+ - **PAT** — a static `access_token`.
103
+ - **GitHub App** — `app_id` + `private_key`; the plugin signs an App JWT
104
+ and mints a short-lived **installation token** (cached process-wide
105
+ until shortly before it expires), so no static, expiring token is
106
+ stored. `installation_id` is optional — when unset it is discovered
107
+ from the pushed repository (`GET /repos/{owner}/{repo}/installation`).
108
+ The App needs **Contents: Read-only**.
109
+
110
+ ## Integration options
111
+
112
+ Asked once per Integration and delivered to every capability on
113
+ `PluginContext.integration_options`:
114
+
115
+ | Option | Required | Description |
116
+ | -------- | --------- | ----------------------------------------------------------------------- |
117
+ | `flavor` | yes | `github`, `ghec`, or `ghes`. |
118
+ | `host` | GHEC/GHES | Tenant or appliance host (e.g. `tenant.ghe.com`, `github.example.com`). |
119
+
120
+ ## Capability options
121
+
122
+ Scoped to one capability and delivered on
123
+ `PluginContext.capability_options`:
124
+
125
+ | Capability | Option | Description |
126
+ | ----------- | -------------------- | --------------------------------------------------------------------------------------- |
127
+ | `identity` | `default_scopes` | Space-separated OAuth scopes (default: `read:user user:email repo workflow`). |
128
+ | `lifecycle` | `archive_target_org` | Org to transfer repos to before archiving; blank archives in place. |
129
+ | `lifecycle` | `create_org` | Default org for repo creation when no `org_mapping` entry matches. |
130
+ | `lifecycle` | `org_mapping` | Per-project-type-slug org overrides; the first match wins over `create_org`. |
131
+
132
+ ## Credentials
133
+
134
+ One credential store per Integration — every capability receives the
135
+ same decrypted blob. All fields are individually optional and validated
136
+ per call, so an identity-only or App-only Integration is valid:
137
+
138
+ | Field | Used by | Description |
139
+ | ----------------- | ------------------ | ------------------------------------------------- |
140
+ | `access_token` | service (PAT mode) | Static personal/service token. |
141
+ | `app_id` | service (App mode) | GitHub App identifier. |
142
+ | `private_key` | service (App mode) | App private key — raw PEM or base64-encoded PEM. |
143
+ | `installation_id` | service (App mode) | Optional; discovered from the repo when unset. |
144
+ | `client_id` | `identity` | OAuth App client id. |
145
+ | `client_secret` | `identity` | OAuth App client secret. |
146
+
147
+ For `commit-sync`, `pr-sync`, and `deployment` provide **either**
148
+ `access_token` **or** `app_id` + `private_key`. `lifecycle` acts as the
149
+ user and takes only `access_token` (or `token`) — it does not fall back
150
+ to GitHub App credentials.
151
+
152
+ ## License
153
+
154
+ BSD-3-Clause.
@@ -0,0 +1,135 @@
1
+ # imbi-plugin-github
2
+
3
+ GitHub plugin for Imbi. A single plugin — slug **`github`** — backs every
4
+ GitHub Integration; the integration-level `flavor` option selects
5
+ github.com (`github`), GitHub Enterprise Cloud (`ghec`), or GitHub
6
+ Enterprise Server (`ghes`), and `host` names the tenant or appliance.
7
+
8
+ ## Capabilities
9
+
10
+ | Kind | Handler |
11
+ | ----------------- | ------------------------- |
12
+ | `identity` | `GitHubIdentity` |
13
+ | `deployment` | `GitHubDeployment` |
14
+ | `lifecycle` | `GitHubLifecycle` |
15
+ | `webhook-actions` | `GitHubWebhookActions` |
16
+ | `commit-sync` | `GitHubCommitSync` |
17
+ | `pr-sync` | `GitHubPullRequestSync` |
18
+ | `analysis` | `GitHubDoctor` |
19
+
20
+ ### Identity
21
+
22
+ Implements the OAuth App flow. The access token returned by the OAuth
23
+ grant is passed straight to GitHub APIs as a `Bearer` token, so
24
+ `materialize()` is a no-op.
25
+
26
+ ### Deployment
27
+
28
+ Drives the GitHub Deployments API (`POST /repos/{owner}/{repo}/deployments`)
29
+ plus tag and release creation. Promote behaviour is inferred from the
30
+ ref shape by the host (semver → trigger Deployment, raw SHA → cut tag
31
+ + Release). Per-env workflow inputs ride on the `USES_PLUGIN` edge as
32
+ `env_payloads` and arrive on `PluginContext.environment_config`.
33
+
34
+ ### Lifecycle
35
+
36
+ Reacts to project archive / unarchive by archiving the matching repo via
37
+ `PATCH /repos/{owner}/{repo}` with `{"archived": true|false}`. When the
38
+ `archive_target_org` option is set, archive **also** transfers the repo to
39
+ that org first via `POST /repos/{owner}/{repo}/transfer` — useful for
40
+ moving sunset projects into a dedicated "archive" org so they no longer
41
+ crowd primary-org searches.
42
+
43
+ GitHub refuses to transfer archived repos, so an already-archived source
44
+ is briefly unarchived, transferred, and re-archived at the destination.
45
+ On unarchive the plugin only flips `archived` back to `false` at the
46
+ repo's current location — it does **not** transfer back to the original
47
+ org.
48
+
49
+ Archiving requires admin scope on the repo; transferring additionally
50
+ requires admin permission on the target organization.
51
+
52
+ ### Webhook actions (commit / tag / PR sync)
53
+
54
+ The `webhook-actions` capability exposes the actions the gateway
55
+ dispatches from webhook deliveries. A `WebhookRule.handler` is
56
+ `"<plugin_slug>#<action_name>"`, and the slug is the **plugin** slug —
57
+ `github` — not the capability kind:
58
+
59
+ | Action | Handler | Records into ClickHouse |
60
+ | --------------------- | ---------------------------- | ----------------------- |
61
+ | `sync_commits` | `github#sync_commits` | `commits` |
62
+ | `sync_tags` | `github#sync_tags` | `tags` |
63
+ | `sync_pull_requests` | `github#sync_pull_requests` | `pull_requests` |
64
+
65
+ `sync_commits` and `sync_tags` are dispatched from `push` deliveries;
66
+ `sync_pull_requests` from `pull_request` deliveries.
67
+
68
+ `sync_commits` fetches the full set of commits in a push via the compare
69
+ API (paginated, so it isn't capped by the 20-commit inline payload limit);
70
+ `sync_tags` records the pushed tag and, with `reconcile_all`, the repo's
71
+ full tag list. Branch/tag gating is the rule's CEL `filter_expression`,
72
+ which evaluates against the recorded event — the webhook body is under
73
+ `payload` (e.g. `payload.ref == "refs/heads/main"`,
74
+ `payload.ref.startsWith("refs/tags/")`). The API
75
+ flavor (github.com / GHEC / GHES) is resolved at runtime — explicit
76
+ `api_base_url`, else a connected GitHub plugin on the same service, else
77
+ the service endpoint, else the payload's `repository.url`.
78
+
79
+ Unlike identity/deployment/lifecycle (which act as the OAuth user),
80
+ commit-sync runs without an actor and authenticates with a **service**
81
+ credential in one of two modes, resolved per call:
82
+
83
+ - **PAT** — a static `access_token`.
84
+ - **GitHub App** — `app_id` + `private_key`; the plugin signs an App JWT
85
+ and mints a short-lived **installation token** (cached process-wide
86
+ until shortly before it expires), so no static, expiring token is
87
+ stored. `installation_id` is optional — when unset it is discovered
88
+ from the pushed repository (`GET /repos/{owner}/{repo}/installation`).
89
+ The App needs **Contents: Read-only**.
90
+
91
+ ## Integration options
92
+
93
+ Asked once per Integration and delivered to every capability on
94
+ `PluginContext.integration_options`:
95
+
96
+ | Option | Required | Description |
97
+ | -------- | --------- | ----------------------------------------------------------------------- |
98
+ | `flavor` | yes | `github`, `ghec`, or `ghes`. |
99
+ | `host` | GHEC/GHES | Tenant or appliance host (e.g. `tenant.ghe.com`, `github.example.com`). |
100
+
101
+ ## Capability options
102
+
103
+ Scoped to one capability and delivered on
104
+ `PluginContext.capability_options`:
105
+
106
+ | Capability | Option | Description |
107
+ | ----------- | -------------------- | --------------------------------------------------------------------------------------- |
108
+ | `identity` | `default_scopes` | Space-separated OAuth scopes (default: `read:user user:email repo workflow`). |
109
+ | `lifecycle` | `archive_target_org` | Org to transfer repos to before archiving; blank archives in place. |
110
+ | `lifecycle` | `create_org` | Default org for repo creation when no `org_mapping` entry matches. |
111
+ | `lifecycle` | `org_mapping` | Per-project-type-slug org overrides; the first match wins over `create_org`. |
112
+
113
+ ## Credentials
114
+
115
+ One credential store per Integration — every capability receives the
116
+ same decrypted blob. All fields are individually optional and validated
117
+ per call, so an identity-only or App-only Integration is valid:
118
+
119
+ | Field | Used by | Description |
120
+ | ----------------- | ------------------ | ------------------------------------------------- |
121
+ | `access_token` | service (PAT mode) | Static personal/service token. |
122
+ | `app_id` | service (App mode) | GitHub App identifier. |
123
+ | `private_key` | service (App mode) | App private key — raw PEM or base64-encoded PEM. |
124
+ | `installation_id` | service (App mode) | Optional; discovered from the repo when unset. |
125
+ | `client_id` | `identity` | OAuth App client id. |
126
+ | `client_secret` | `identity` | OAuth App client secret. |
127
+
128
+ For `commit-sync`, `pr-sync`, and `deployment` provide **either**
129
+ `access_token` **or** `app_id` + `private_key`. `lifecycle` acts as the
130
+ user and takes only `access_token` (or `token`) — it does not fall back
131
+ to GitHub App credentials.
132
+
133
+ ## License
134
+
135
+ BSD-3-Clause.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "imbi-plugin-github"
3
- version = "2.18.0"
3
+ version = "2.20.0"
4
4
  description = "GitHub identity plugin for Imbi (github.com / GHEC / GHES)"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.14"
@@ -18,7 +18,7 @@ classifiers = [
18
18
  ]
19
19
  dependencies = [
20
20
  "httpx>=0.27",
21
- "imbi-common[databases]==2.18.0",
21
+ "imbi-common[databases]==2.20.0",
22
22
  "pydantic>=2",
23
23
  "pyjwt[crypto]>=2.8",
24
24
  ]
@@ -0,0 +1,135 @@
1
+ # imbi-plugin-github
2
+
3
+ GitHub plugin for Imbi. A single plugin — slug **`github`** — backs every
4
+ GitHub Integration; the integration-level `flavor` option selects
5
+ github.com (`github`), GitHub Enterprise Cloud (`ghec`), or GitHub
6
+ Enterprise Server (`ghes`), and `host` names the tenant or appliance.
7
+
8
+ ## Capabilities
9
+
10
+ | Kind | Handler |
11
+ | ----------------- | ------------------------- |
12
+ | `identity` | `GitHubIdentity` |
13
+ | `deployment` | `GitHubDeployment` |
14
+ | `lifecycle` | `GitHubLifecycle` |
15
+ | `webhook-actions` | `GitHubWebhookActions` |
16
+ | `commit-sync` | `GitHubCommitSync` |
17
+ | `pr-sync` | `GitHubPullRequestSync` |
18
+ | `analysis` | `GitHubDoctor` |
19
+
20
+ ### Identity
21
+
22
+ Implements the OAuth App flow. The access token returned by the OAuth
23
+ grant is passed straight to GitHub APIs as a `Bearer` token, so
24
+ `materialize()` is a no-op.
25
+
26
+ ### Deployment
27
+
28
+ Drives the GitHub Deployments API (`POST /repos/{owner}/{repo}/deployments`)
29
+ plus tag and release creation. Promote behaviour is inferred from the
30
+ ref shape by the host (semver → trigger Deployment, raw SHA → cut tag
31
+ + Release). Per-env workflow inputs ride on the `USES_PLUGIN` edge as
32
+ `env_payloads` and arrive on `PluginContext.environment_config`.
33
+
34
+ ### Lifecycle
35
+
36
+ Reacts to project archive / unarchive by archiving the matching repo via
37
+ `PATCH /repos/{owner}/{repo}` with `{"archived": true|false}`. When the
38
+ `archive_target_org` option is set, archive **also** transfers the repo to
39
+ that org first via `POST /repos/{owner}/{repo}/transfer` — useful for
40
+ moving sunset projects into a dedicated "archive" org so they no longer
41
+ crowd primary-org searches.
42
+
43
+ GitHub refuses to transfer archived repos, so an already-archived source
44
+ is briefly unarchived, transferred, and re-archived at the destination.
45
+ On unarchive the plugin only flips `archived` back to `false` at the
46
+ repo's current location — it does **not** transfer back to the original
47
+ org.
48
+
49
+ Archiving requires admin scope on the repo; transferring additionally
50
+ requires admin permission on the target organization.
51
+
52
+ ### Webhook actions (commit / tag / PR sync)
53
+
54
+ The `webhook-actions` capability exposes the actions the gateway
55
+ dispatches from webhook deliveries. A `WebhookRule.handler` is
56
+ `"<plugin_slug>#<action_name>"`, and the slug is the **plugin** slug —
57
+ `github` — not the capability kind:
58
+
59
+ | Action | Handler | Records into ClickHouse |
60
+ | --------------------- | ---------------------------- | ----------------------- |
61
+ | `sync_commits` | `github#sync_commits` | `commits` |
62
+ | `sync_tags` | `github#sync_tags` | `tags` |
63
+ | `sync_pull_requests` | `github#sync_pull_requests` | `pull_requests` |
64
+
65
+ `sync_commits` and `sync_tags` are dispatched from `push` deliveries;
66
+ `sync_pull_requests` from `pull_request` deliveries.
67
+
68
+ `sync_commits` fetches the full set of commits in a push via the compare
69
+ API (paginated, so it isn't capped by the 20-commit inline payload limit);
70
+ `sync_tags` records the pushed tag and, with `reconcile_all`, the repo's
71
+ full tag list. Branch/tag gating is the rule's CEL `filter_expression`,
72
+ which evaluates against the recorded event — the webhook body is under
73
+ `payload` (e.g. `payload.ref == "refs/heads/main"`,
74
+ `payload.ref.startsWith("refs/tags/")`). The API
75
+ flavor (github.com / GHEC / GHES) is resolved at runtime — explicit
76
+ `api_base_url`, else a connected GitHub plugin on the same service, else
77
+ the service endpoint, else the payload's `repository.url`.
78
+
79
+ Unlike identity/deployment/lifecycle (which act as the OAuth user),
80
+ commit-sync runs without an actor and authenticates with a **service**
81
+ credential in one of two modes, resolved per call:
82
+
83
+ - **PAT** — a static `access_token`.
84
+ - **GitHub App** — `app_id` + `private_key`; the plugin signs an App JWT
85
+ and mints a short-lived **installation token** (cached process-wide
86
+ until shortly before it expires), so no static, expiring token is
87
+ stored. `installation_id` is optional — when unset it is discovered
88
+ from the pushed repository (`GET /repos/{owner}/{repo}/installation`).
89
+ The App needs **Contents: Read-only**.
90
+
91
+ ## Integration options
92
+
93
+ Asked once per Integration and delivered to every capability on
94
+ `PluginContext.integration_options`:
95
+
96
+ | Option | Required | Description |
97
+ | -------- | --------- | ----------------------------------------------------------------------- |
98
+ | `flavor` | yes | `github`, `ghec`, or `ghes`. |
99
+ | `host` | GHEC/GHES | Tenant or appliance host (e.g. `tenant.ghe.com`, `github.example.com`). |
100
+
101
+ ## Capability options
102
+
103
+ Scoped to one capability and delivered on
104
+ `PluginContext.capability_options`:
105
+
106
+ | Capability | Option | Description |
107
+ | ----------- | -------------------- | --------------------------------------------------------------------------------------- |
108
+ | `identity` | `default_scopes` | Space-separated OAuth scopes (default: `read:user user:email repo workflow`). |
109
+ | `lifecycle` | `archive_target_org` | Org to transfer repos to before archiving; blank archives in place. |
110
+ | `lifecycle` | `create_org` | Default org for repo creation when no `org_mapping` entry matches. |
111
+ | `lifecycle` | `org_mapping` | Per-project-type-slug org overrides; the first match wins over `create_org`. |
112
+
113
+ ## Credentials
114
+
115
+ One credential store per Integration — every capability receives the
116
+ same decrypted blob. All fields are individually optional and validated
117
+ per call, so an identity-only or App-only Integration is valid:
118
+
119
+ | Field | Used by | Description |
120
+ | ----------------- | ------------------ | ------------------------------------------------- |
121
+ | `access_token` | service (PAT mode) | Static personal/service token. |
122
+ | `app_id` | service (App mode) | GitHub App identifier. |
123
+ | `private_key` | service (App mode) | App private key — raw PEM or base64-encoded PEM. |
124
+ | `installation_id` | service (App mode) | Optional; discovered from the repo when unset. |
125
+ | `client_id` | `identity` | OAuth App client id. |
126
+ | `client_secret` | `identity` | OAuth App client secret. |
127
+
128
+ For `commit-sync`, `pr-sync`, and `deployment` provide **either**
129
+ `access_token` **or** `app_id` + `private_key`. `lifecycle` acts as the
130
+ user and takes only `access_token` (or `token`) — it does not fall back
131
+ to GitHub App credentials.
132
+
133
+ ## License
134
+
135
+ BSD-3-Clause.
@@ -1,126 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: imbi-plugin-github
3
- Version: 2.18.0
4
- Summary: GitHub identity plugin for Imbi (github.com / GHEC / GHES)
5
- Author-email: "Gavin M. Roy" <gavinr@aweber.com>
6
- License-Expression: BSD-3-Clause
7
- Classifier: Development Status :: 3 - Alpha
8
- Classifier: Intended Audience :: Developers
9
- Classifier: Natural Language :: English
10
- Classifier: Operating System :: OS Independent
11
- Classifier: Programming Language :: Python :: 3
12
- Classifier: Programming Language :: Python :: 3.14
13
- Requires-Python: >=3.14
14
- Requires-Dist: httpx>=0.27
15
- Requires-Dist: imbi-common[databases]==2.18.0
16
- Requires-Dist: pydantic>=2
17
- Requires-Dist: pyjwt[crypto]>=2.8
18
- Description-Content-Type: text/markdown
19
-
20
- # imbi-plugin-github
21
-
22
- GitHub plugins for Imbi. Three flavors (github.com, GitHub Enterprise Cloud,
23
- GitHub Enterprise Server) of each plugin type so the admin UI can wire
24
- projects to the right backend.
25
-
26
- ## Plugin types
27
-
28
- | Type | Slugs |
29
- | ---------- | -------------------------------------------------------------------- |
30
- | Identity | `github`, `github-enterprise-cloud`, `github-enterprise-server` |
31
- | Deployment | `github-deployment`, `github-deployment-ec`, `github-deployment-es` |
32
- | Lifecycle | `github-lifecycle`, `github-lifecycle-ec`, `github-lifecycle-es` |
33
- | Webhook | `github-commit-sync` |
34
-
35
- ### Identity
36
-
37
- Implements the OAuth App flow. The access token returned by the OAuth
38
- grant is passed straight to GitHub APIs as a `Bearer` token, so
39
- `materialize()` is a no-op.
40
-
41
- ### Deployment
42
-
43
- Drives the GitHub Deployments API (`POST /repos/{owner}/{repo}/deployments`)
44
- plus tag and release creation. Promote behaviour is inferred from the
45
- ref shape by the host (semver → trigger Deployment, raw SHA → cut tag
46
- + Release). Per-env workflow inputs ride on the `USES_PLUGIN` edge as
47
- `env_payloads` and arrive on `PluginContext.environment_config`.
48
-
49
- ### Lifecycle
50
-
51
- Reacts to project archive / unarchive by archiving the matching repo via
52
- `PATCH /repos/{owner}/{repo}` with `{"archived": true|false}`. When the
53
- `archive_target_org` option is set, archive **also** transfers the repo to
54
- that org first via `POST /repos/{owner}/{repo}/transfer` — useful for
55
- moving sunset projects into a dedicated "archive" org so they no longer
56
- crowd primary-org searches.
57
-
58
- GitHub refuses to transfer archived repos, so an already-archived source
59
- is briefly unarchived, transferred, and re-archived at the destination.
60
- On unarchive the plugin only flips `archived` back to `false` at the
61
- repo's current location — it does **not** transfer back to the original
62
- org.
63
-
64
- Archiving requires admin scope on the repo; transferring additionally
65
- requires admin permission on the target organization.
66
-
67
- ### Webhook (commit / tag sync)
68
-
69
- A single `github-commit-sync` webhook-action plugin exposes two actions
70
- the gateway dispatches on `push` deliveries:
71
-
72
- | Action | Handler | Records into ClickHouse |
73
- | -------------- | -------------------------------- | ----------------------- |
74
- | `sync_commits` | `github-commit-sync#sync_commits`| `commits` |
75
- | `sync_tags` | `github-commit-sync#sync_tags` | `tags` |
76
-
77
- `sync_commits` fetches the full set of commits in a push via the compare
78
- API (paginated, so it isn't capped by the 20-commit inline payload limit);
79
- `sync_tags` records the pushed tag and, with `reconcile_all`, the repo's
80
- full tag list. Branch/tag gating is the rule's CEL `filter_expression`
81
- (e.g. `ref == "refs/heads/main"`, `ref.startsWith("refs/tags/")`). The API
82
- flavor (github.com / GHEC / GHES) is resolved at runtime — explicit
83
- `api_base_url`, else a connected GitHub plugin on the same service, else
84
- the service endpoint, else the payload's `repository.url`.
85
-
86
- Unlike identity/deployment/lifecycle (which act as the OAuth user),
87
- commit-sync runs without an actor and authenticates with a **service**
88
- credential in one of two modes, resolved per call:
89
-
90
- - **PAT** — a static `access_token`.
91
- - **GitHub App** — `app_id` + `private_key`; the plugin signs an App JWT
92
- and mints a short-lived **installation token** (cached process-wide
93
- until shortly before it expires), so no static, expiring token is
94
- stored. `installation_id` is optional — when unset it is discovered
95
- from the pushed repository (`GET /repos/{owner}/{repo}/installation`).
96
- The App needs **Contents: Read-only**.
97
-
98
- ## Manifest options (identity)
99
-
100
- | Option | Required | Description |
101
- | ---------------- | --------- | -------------------------------------------------------------------------- |
102
- | `host` | GHEC/GHES | Tenant or appliance host (e.g. `tenant.ghe.com`, `github.example.com`). |
103
- | `default_scopes` | no | Space-separated default OAuth scopes (default: `read:user user:email repo workflow`). |
104
-
105
- ## Credentials (identity)
106
-
107
- | Field | Required |
108
- | ---------------- | -------- |
109
- | `client_id` | yes |
110
- | `client_secret` | yes |
111
-
112
- ## Credentials (commit-sync)
113
-
114
- Provide **either** the PAT field **or** the GitHub App fields (all
115
- individually optional; validated per call):
116
-
117
- | Field | Mode | Description |
118
- | ----------------- | ---- | ------------------------------------------------------ |
119
- | `access_token` | PAT | Static personal/service token. |
120
- | `app_id` | App | GitHub App identifier. |
121
- | `private_key` | App | App private key — raw PEM or base64-encoded PEM. |
122
- | `installation_id` | App | Optional; discovered from the repo when unset. |
123
-
124
- ## License
125
-
126
- BSD-3-Clause.
@@ -1,107 +0,0 @@
1
- # imbi-plugin-github
2
-
3
- GitHub plugins for Imbi. Three flavors (github.com, GitHub Enterprise Cloud,
4
- GitHub Enterprise Server) of each plugin type so the admin UI can wire
5
- projects to the right backend.
6
-
7
- ## Plugin types
8
-
9
- | Type | Slugs |
10
- | ---------- | -------------------------------------------------------------------- |
11
- | Identity | `github`, `github-enterprise-cloud`, `github-enterprise-server` |
12
- | Deployment | `github-deployment`, `github-deployment-ec`, `github-deployment-es` |
13
- | Lifecycle | `github-lifecycle`, `github-lifecycle-ec`, `github-lifecycle-es` |
14
- | Webhook | `github-commit-sync` |
15
-
16
- ### Identity
17
-
18
- Implements the OAuth App flow. The access token returned by the OAuth
19
- grant is passed straight to GitHub APIs as a `Bearer` token, so
20
- `materialize()` is a no-op.
21
-
22
- ### Deployment
23
-
24
- Drives the GitHub Deployments API (`POST /repos/{owner}/{repo}/deployments`)
25
- plus tag and release creation. Promote behaviour is inferred from the
26
- ref shape by the host (semver → trigger Deployment, raw SHA → cut tag
27
- + Release). Per-env workflow inputs ride on the `USES_PLUGIN` edge as
28
- `env_payloads` and arrive on `PluginContext.environment_config`.
29
-
30
- ### Lifecycle
31
-
32
- Reacts to project archive / unarchive by archiving the matching repo via
33
- `PATCH /repos/{owner}/{repo}` with `{"archived": true|false}`. When the
34
- `archive_target_org` option is set, archive **also** transfers the repo to
35
- that org first via `POST /repos/{owner}/{repo}/transfer` — useful for
36
- moving sunset projects into a dedicated "archive" org so they no longer
37
- crowd primary-org searches.
38
-
39
- GitHub refuses to transfer archived repos, so an already-archived source
40
- is briefly unarchived, transferred, and re-archived at the destination.
41
- On unarchive the plugin only flips `archived` back to `false` at the
42
- repo's current location — it does **not** transfer back to the original
43
- org.
44
-
45
- Archiving requires admin scope on the repo; transferring additionally
46
- requires admin permission on the target organization.
47
-
48
- ### Webhook (commit / tag sync)
49
-
50
- A single `github-commit-sync` webhook-action plugin exposes two actions
51
- the gateway dispatches on `push` deliveries:
52
-
53
- | Action | Handler | Records into ClickHouse |
54
- | -------------- | -------------------------------- | ----------------------- |
55
- | `sync_commits` | `github-commit-sync#sync_commits`| `commits` |
56
- | `sync_tags` | `github-commit-sync#sync_tags` | `tags` |
57
-
58
- `sync_commits` fetches the full set of commits in a push via the compare
59
- API (paginated, so it isn't capped by the 20-commit inline payload limit);
60
- `sync_tags` records the pushed tag and, with `reconcile_all`, the repo's
61
- full tag list. Branch/tag gating is the rule's CEL `filter_expression`
62
- (e.g. `ref == "refs/heads/main"`, `ref.startsWith("refs/tags/")`). The API
63
- flavor (github.com / GHEC / GHES) is resolved at runtime — explicit
64
- `api_base_url`, else a connected GitHub plugin on the same service, else
65
- the service endpoint, else the payload's `repository.url`.
66
-
67
- Unlike identity/deployment/lifecycle (which act as the OAuth user),
68
- commit-sync runs without an actor and authenticates with a **service**
69
- credential in one of two modes, resolved per call:
70
-
71
- - **PAT** — a static `access_token`.
72
- - **GitHub App** — `app_id` + `private_key`; the plugin signs an App JWT
73
- and mints a short-lived **installation token** (cached process-wide
74
- until shortly before it expires), so no static, expiring token is
75
- stored. `installation_id` is optional — when unset it is discovered
76
- from the pushed repository (`GET /repos/{owner}/{repo}/installation`).
77
- The App needs **Contents: Read-only**.
78
-
79
- ## Manifest options (identity)
80
-
81
- | Option | Required | Description |
82
- | ---------------- | --------- | -------------------------------------------------------------------------- |
83
- | `host` | GHEC/GHES | Tenant or appliance host (e.g. `tenant.ghe.com`, `github.example.com`). |
84
- | `default_scopes` | no | Space-separated default OAuth scopes (default: `read:user user:email repo workflow`). |
85
-
86
- ## Credentials (identity)
87
-
88
- | Field | Required |
89
- | ---------------- | -------- |
90
- | `client_id` | yes |
91
- | `client_secret` | yes |
92
-
93
- ## Credentials (commit-sync)
94
-
95
- Provide **either** the PAT field **or** the GitHub App fields (all
96
- individually optional; validated per call):
97
-
98
- | Field | Mode | Description |
99
- | ----------------- | ---- | ------------------------------------------------------ |
100
- | `access_token` | PAT | Static personal/service token. |
101
- | `app_id` | App | GitHub App identifier. |
102
- | `private_key` | App | App private key — raw PEM or base64-encoded PEM. |
103
- | `installation_id` | App | Optional; discovered from the repo when unset. |
104
-
105
- ## License
106
-
107
- BSD-3-Clause.
@@ -1,107 +0,0 @@
1
- # imbi-plugin-github
2
-
3
- GitHub plugins for Imbi. Three flavors (github.com, GitHub Enterprise Cloud,
4
- GitHub Enterprise Server) of each plugin type so the admin UI can wire
5
- projects to the right backend.
6
-
7
- ## Plugin types
8
-
9
- | Type | Slugs |
10
- | ---------- | -------------------------------------------------------------------- |
11
- | Identity | `github`, `github-enterprise-cloud`, `github-enterprise-server` |
12
- | Deployment | `github-deployment`, `github-deployment-ec`, `github-deployment-es` |
13
- | Lifecycle | `github-lifecycle`, `github-lifecycle-ec`, `github-lifecycle-es` |
14
- | Webhook | `github-commit-sync` |
15
-
16
- ### Identity
17
-
18
- Implements the OAuth App flow. The access token returned by the OAuth
19
- grant is passed straight to GitHub APIs as a `Bearer` token, so
20
- `materialize()` is a no-op.
21
-
22
- ### Deployment
23
-
24
- Drives the GitHub Deployments API (`POST /repos/{owner}/{repo}/deployments`)
25
- plus tag and release creation. Promote behaviour is inferred from the
26
- ref shape by the host (semver → trigger Deployment, raw SHA → cut tag
27
- + Release). Per-env workflow inputs ride on the `USES_PLUGIN` edge as
28
- `env_payloads` and arrive on `PluginContext.environment_config`.
29
-
30
- ### Lifecycle
31
-
32
- Reacts to project archive / unarchive by archiving the matching repo via
33
- `PATCH /repos/{owner}/{repo}` with `{"archived": true|false}`. When the
34
- `archive_target_org` option is set, archive **also** transfers the repo to
35
- that org first via `POST /repos/{owner}/{repo}/transfer` — useful for
36
- moving sunset projects into a dedicated "archive" org so they no longer
37
- crowd primary-org searches.
38
-
39
- GitHub refuses to transfer archived repos, so an already-archived source
40
- is briefly unarchived, transferred, and re-archived at the destination.
41
- On unarchive the plugin only flips `archived` back to `false` at the
42
- repo's current location — it does **not** transfer back to the original
43
- org.
44
-
45
- Archiving requires admin scope on the repo; transferring additionally
46
- requires admin permission on the target organization.
47
-
48
- ### Webhook (commit / tag sync)
49
-
50
- A single `github-commit-sync` webhook-action plugin exposes two actions
51
- the gateway dispatches on `push` deliveries:
52
-
53
- | Action | Handler | Records into ClickHouse |
54
- | -------------- | -------------------------------- | ----------------------- |
55
- | `sync_commits` | `github-commit-sync#sync_commits`| `commits` |
56
- | `sync_tags` | `github-commit-sync#sync_tags` | `tags` |
57
-
58
- `sync_commits` fetches the full set of commits in a push via the compare
59
- API (paginated, so it isn't capped by the 20-commit inline payload limit);
60
- `sync_tags` records the pushed tag and, with `reconcile_all`, the repo's
61
- full tag list. Branch/tag gating is the rule's CEL `filter_expression`
62
- (e.g. `ref == "refs/heads/main"`, `ref.startsWith("refs/tags/")`). The API
63
- flavor (github.com / GHEC / GHES) is resolved at runtime — explicit
64
- `api_base_url`, else a connected GitHub plugin on the same service, else
65
- the service endpoint, else the payload's `repository.url`.
66
-
67
- Unlike identity/deployment/lifecycle (which act as the OAuth user),
68
- commit-sync runs without an actor and authenticates with a **service**
69
- credential in one of two modes, resolved per call:
70
-
71
- - **PAT** — a static `access_token`.
72
- - **GitHub App** — `app_id` + `private_key`; the plugin signs an App JWT
73
- and mints a short-lived **installation token** (cached process-wide
74
- until shortly before it expires), so no static, expiring token is
75
- stored. `installation_id` is optional — when unset it is discovered
76
- from the pushed repository (`GET /repos/{owner}/{repo}/installation`).
77
- The App needs **Contents: Read-only**.
78
-
79
- ## Manifest options (identity)
80
-
81
- | Option | Required | Description |
82
- | ---------------- | --------- | -------------------------------------------------------------------------- |
83
- | `host` | GHEC/GHES | Tenant or appliance host (e.g. `tenant.ghe.com`, `github.example.com`). |
84
- | `default_scopes` | no | Space-separated default OAuth scopes (default: `read:user user:email repo workflow`). |
85
-
86
- ## Credentials (identity)
87
-
88
- | Field | Required |
89
- | ---------------- | -------- |
90
- | `client_id` | yes |
91
- | `client_secret` | yes |
92
-
93
- ## Credentials (commit-sync)
94
-
95
- Provide **either** the PAT field **or** the GitHub App fields (all
96
- individually optional; validated per call):
97
-
98
- | Field | Mode | Description |
99
- | ----------------- | ---- | ------------------------------------------------------ |
100
- | `access_token` | PAT | Static personal/service token. |
101
- | `app_id` | App | GitHub App identifier. |
102
- | `private_key` | App | App private key — raw PEM or base64-encoded PEM. |
103
- | `installation_id` | App | Optional; discovered from the repo when unset. |
104
-
105
- ## License
106
-
107
- BSD-3-Clause.