From 2b41a0bb176038f4bb6d6f06ed8cf3f83879cefc Mon Sep 17 00:00:00 2001 From: Svilen Stefanov Date: Thu, 24 Sep 2026 22:29:15 +0200 Subject: [PATCH 1/2] chore: refresh the vendored licensing contracts Copied from CodeBoarding/licensing-aws contracts/ at paywall/4-usage (ca99a1b): the optional pull_request on /run/start, the usage and workspace-usage schemas, and me.orgs[].admin. Co-Authored-By: Claude Opus 5.5 (1M context) --- tests/contracts/README.md | 2 + .../contracts/examples/me.free-exhausted.json | 1 + .../contracts/examples/me.free-one-left.json | 1 + tests/contracts/examples/me.past-due.json | 1 + tests/contracts/examples/me.pro.json | 1 + tests/contracts/examples/me.team.json | 1 + tests/contracts/examples/me.trial.json | 1 + .../examples/run-start.request.comment.json | 11 + .../examples/usage.free-near-limit.json | 75 ++++++ tests/contracts/examples/usage.pro.json | 120 ++++++++++ tests/contracts/examples/usage.team.json | 60 +++++ .../examples/workspace-usage.team.json | 44 ++++ tests/contracts/me.schema.json | 5 + tests/contracts/run-start.request.schema.json | 5 + tests/contracts/usage.schema.json | 213 ++++++++++++++++++ tests/contracts/workspace-usage.schema.json | 120 ++++++++++ 16 files changed, 661 insertions(+) create mode 100644 tests/contracts/examples/run-start.request.comment.json create mode 100644 tests/contracts/examples/usage.free-near-limit.json create mode 100644 tests/contracts/examples/usage.pro.json create mode 100644 tests/contracts/examples/usage.team.json create mode 100644 tests/contracts/examples/workspace-usage.team.json create mode 100644 tests/contracts/usage.schema.json create mode 100644 tests/contracts/workspace-usage.schema.json diff --git a/tests/contracts/README.md b/tests/contracts/README.md index 65717a2..0365642 100644 --- a/tests/contracts/README.md +++ b/tests/contracts/README.md @@ -6,6 +6,8 @@ JSON Schemas (draft 2020-12) for the wire shapes licensing-aws answers and accep | --- | --- | | `session.schema.json` | answer of `POST /session/github` and `POST /session/extension` | | `me.schema.json` | answer of `GET /me` | +| `usage.schema.json` | answer of `GET /me/usage`: this week's counted runs and opened private reviews, item by item | +| `workspace-usage.schema.json` | answer of `GET /workspaces/{workspace}/usage` (admins of a Team or Enterprise organisation; 403 `reason: not_admin` or `no_plan` otherwise) | | `run-start.request.schema.json`, `run-start.response.schema.json` | `POST /run/start` on gha_proxy (OIDC) and license_proxy (extension token) | | `run-finish.request.schema.json`, `run-finish.response.schema.json` | `POST /run/finish` on both | | `meter-consume.request.schema.json`, `meter-consume.response.schema.json` | `POST /meter/consume` | diff --git a/tests/contracts/examples/me.free-exhausted.json b/tests/contracts/examples/me.free-exhausted.json index 85b2121..a16acdc 100644 --- a/tests/contracts/examples/me.free-exhausted.json +++ b/tests/contracts/examples/me.free-exhausted.json @@ -44,6 +44,7 @@ "login": "acme-corp", "plan": "free", "covered": false, + "admin": false, "members_permission": true, "bot_runs": { "meter": "bot_runs", diff --git a/tests/contracts/examples/me.free-one-left.json b/tests/contracts/examples/me.free-one-left.json index b29781e..31073ba 100644 --- a/tests/contracts/examples/me.free-one-left.json +++ b/tests/contracts/examples/me.free-one-left.json @@ -44,6 +44,7 @@ "login": "acme-corp", "plan": "free", "covered": false, + "admin": false, "members_permission": true, "bot_runs": { "meter": "bot_runs", diff --git a/tests/contracts/examples/me.past-due.json b/tests/contracts/examples/me.past-due.json index 80d76d8..b991a45 100644 --- a/tests/contracts/examples/me.past-due.json +++ b/tests/contracts/examples/me.past-due.json @@ -44,6 +44,7 @@ "login": "acme-corp", "plan": "free", "covered": false, + "admin": false, "members_permission": true, "bot_runs": { "meter": "bot_runs", diff --git a/tests/contracts/examples/me.pro.json b/tests/contracts/examples/me.pro.json index ca59f4f..a210a38 100644 --- a/tests/contracts/examples/me.pro.json +++ b/tests/contracts/examples/me.pro.json @@ -44,6 +44,7 @@ "login": "acme-corp", "plan": "free", "covered": false, + "admin": false, "members_permission": true, "bot_runs": { "meter": "bot_runs", diff --git a/tests/contracts/examples/me.team.json b/tests/contracts/examples/me.team.json index 4276242..08c7770 100644 --- a/tests/contracts/examples/me.team.json +++ b/tests/contracts/examples/me.team.json @@ -47,6 +47,7 @@ "login": "acme-corp", "plan": "team", "covered": true, + "admin": true, "members_permission": true, "bot_runs": { "meter": "bot_runs", diff --git a/tests/contracts/examples/me.trial.json b/tests/contracts/examples/me.trial.json index 2f8c33a..b4519bb 100644 --- a/tests/contracts/examples/me.trial.json +++ b/tests/contracts/examples/me.trial.json @@ -44,6 +44,7 @@ "login": "acme-corp", "plan": "free", "covered": false, + "admin": false, "members_permission": true, "bot_runs": { "meter": "bot_runs", diff --git a/tests/contracts/examples/run-start.request.comment.json b/tests/contracts/examples/run-start.request.comment.json new file mode 100644 index 0000000..7cf230c --- /dev/null +++ b/tests/contracts/examples/run-start.request.comment.json @@ -0,0 +1,11 @@ +{ + "depth": 5, + "credential": "hosted", + "baseline_depth": 2, + "pull_request": 482, + "client": { + "surface": "action", + "version": "1.17.0", + "editor": null + } +} diff --git a/tests/contracts/examples/usage.free-near-limit.json b/tests/contracts/examples/usage.free-near-limit.json new file mode 100644 index 0000000..523387a --- /dev/null +++ b/tests/contracts/examples/usage.free-near-limit.json @@ -0,0 +1,75 @@ +{ + "period": "2026-W39", + "resets_at": "2026-09-28T00:00:00+00:00", + "runs": { + "used": 4, + "limit": 5, + "by_you": 3, + "by_bots": 1, + "items": [ + { + "key": "github:5550101#pr12", + "surface": "github", + "repository": "fresh-dev/todo-api", + "pr": 12, + "by": { + "kind": "person", + "login": "fresh-dev" + }, + "first_run_at": "2026-09-23T10:15:00+00:00", + "updates": 0 + }, + { + "key": "vscode:1b3d5f7092a4c6e8f0a2b4c6d8e0f1a3b5c7d9e1f2a4b6c8d0e2f4a6b8c0d2e4", + "surface": "vscode", + "repository": "todo-api", + "pr": null, + "by": { + "kind": "person", + "login": "fresh-dev" + }, + "first_run_at": "2026-09-22T19:40:00+00:00", + "updates": 1 + }, + { + "key": "github:5550101#pr11", + "surface": "github", + "repository": "fresh-dev/todo-api", + "pr": 11, + "by": { + "kind": "bot", + "login": "renovate[bot]" + }, + "first_run_at": "2026-09-22T06:00:00+00:00", + "updates": 0 + }, + { + "key": "github:5550102#pr3", + "surface": "github", + "repository": null, + "pr": 3, + "by": null, + "first_run_at": null, + "updates": 0 + } + ] + }, + "reviews": { + "used": 2, + "limit": 3, + "items": [ + { + "key": "github:5550101#pr12", + "repository": "fresh-dev/todo-api", + "pr": 12, + "opened_at": "2026-09-23T10:40:00+00:00" + }, + { + "key": "github:5550101#pr10", + "repository": "fresh-dev/todo-api", + "pr": 10, + "opened_at": "2026-09-21T13:05:00+00:00" + } + ] + } +} diff --git a/tests/contracts/examples/usage.pro.json b/tests/contracts/examples/usage.pro.json new file mode 100644 index 0000000..11568b6 --- /dev/null +++ b/tests/contracts/examples/usage.pro.json @@ -0,0 +1,120 @@ +{ + "period": "2026-W39", + "resets_at": "2026-09-28T00:00:00+00:00", + "runs": { + "used": 7, + "limit": 40, + "by_you": 5, + "by_bots": 2, + "items": [ + { + "key": "github:870011#pr2", + "surface": "github", + "repository": "Svilen-Stefanov/paywall-e2e", + "pr": 2, + "by": { + "kind": "person", + "login": "Svilen-Stefanov" + }, + "first_run_at": "2026-09-22T16:40:00+00:00", + "updates": 0 + }, + { + "key": "github:870011#pr1", + "surface": "github", + "repository": "Svilen-Stefanov/paywall-e2e", + "pr": 1, + "by": { + "kind": "person", + "login": "Svilen-Stefanov" + }, + "first_run_at": "2026-09-22T16:09:00+00:00", + "updates": 1 + }, + { + "key": "github:870011#pr4", + "surface": "github", + "repository": "Svilen-Stefanov/paywall-e2e", + "pr": 4, + "by": { + "kind": "bot", + "login": "dependabot[bot]" + }, + "first_run_at": "2026-09-22T08:00:00+00:00", + "updates": 0 + }, + { + "key": "github:9919001#pr31", + "surface": "github", + "repository": "CodeBoarding/CodeBoarding", + "pr": 31, + "by": { + "kind": "person", + "login": "Svilen-Stefanov" + }, + "first_run_at": "2026-09-21T15:20:00+00:00", + "updates": 2 + }, + { + "key": "github:9919002#run11809532110", + "surface": "github", + "repository": "CodeBoarding/CodeBoarding-action", + "pr": null, + "by": { + "kind": "person", + "login": "Svilen-Stefanov" + }, + "first_run_at": "2026-09-21T11:30:00+00:00", + "updates": 0 + }, + { + "key": "vscode:9f2c4e1a7b3d5f60819a2b4c6d8e0f1a3b5c7d9e1f2a4b6c8d0e2f4a6b8c0d2e", + "surface": "vscode", + "repository": "CodeBoarding-webview", + "pr": null, + "by": { + "kind": "person", + "login": "Svilen-Stefanov" + }, + "first_run_at": "2026-09-21T10:02:00+00:00", + "updates": 3 + }, + { + "key": "github:870011#pr3", + "surface": "github", + "repository": "Svilen-Stefanov/paywall-e2e", + "pr": 3, + "by": { + "kind": "bot", + "login": "dependabot[bot]" + }, + "first_run_at": "2026-09-21T08:00:00+00:00", + "updates": 0 + } + ] + }, + "reviews": { + "used": 3, + "limit": 60, + "items": [ + { + "key": "github:9919001#pr31", + "repository": "CodeBoarding/CodeBoarding", + "pr": 31, + "opened_at": "2026-09-23T09:12:00+00:00" + }, + { + "key": "github:9919003#pr163", + "repository": "CodeBoarding/CodeBoarding-webview", + "pr": 163, + "opened_at": "2026-09-22T14:30:00+00:00" + }, + { + "key": "github:9919001#pr28", + "repository": "CodeBoarding/CodeBoarding", + "pr": 28, + "opened_at": "2026-09-21T17:45:00+00:00" + } + ] + } +} diff --git a/tests/contracts/examples/usage.team.json b/tests/contracts/examples/usage.team.json new file mode 100644 index 0000000..a84270a --- /dev/null +++ b/tests/contracts/examples/usage.team.json @@ -0,0 +1,60 @@ +{ + "period": "2026-W39", + "resets_at": "2026-09-28T00:00:00+00:00", + "runs": { + "used": 12, + "limit": 60, + "by_you": 12, + "by_bots": 0, + "items": [ + { + "key": "github:9919001#pr35", + "surface": "github", + "repository": "CodeBoarding/CodeBoarding", + "pr": 35, + "by": { + "kind": "person", + "login": "ivanmilevtues" + }, + "first_run_at": "2026-09-23T11:02:00+00:00", + "updates": 0 + }, + { + "key": "github:9919001#pr34", + "surface": "github", + "repository": "CodeBoarding/CodeBoarding", + "pr": 34, + "by": { + "kind": "person", + "login": "ivanmilevtues" + }, + "first_run_at": "2026-09-23T08:47:00+00:00", + "updates": 4 + }, + { + "key": "vscode:4d6f8a0c2e4f6a8b0c2d4e6f8a0b2c4d6e8f0a2b4c6d8e0f2a4b6c8d0e2f4a6b", + "surface": "vscode", + "repository": "CodeBoarding", + "pr": null, + "by": { + "kind": "person", + "login": "ivanmilevtues" + }, + "first_run_at": "2026-09-22T09:30:00+00:00", + "updates": 6 + } + ] + }, + "reviews": { + "used": 9, + "limit": 100, + "items": [ + { + "key": "github:9919001#pr35", + "repository": "CodeBoarding/CodeBoarding", + "pr": 35, + "opened_at": "2026-09-23T11:20:00+00:00" + } + ] + } +} diff --git a/tests/contracts/examples/workspace-usage.team.json b/tests/contracts/examples/workspace-usage.team.json new file mode 100644 index 0000000..3899135 --- /dev/null +++ b/tests/contracts/examples/workspace-usage.team.json @@ -0,0 +1,44 @@ +{ + "workspace": "workspace:github:9919", + "login": "CodeBoarding", + "plan": "team", + "period": "2026-W39", + "resets_at": "2026-09-28T00:00:00+00:00", + "runs": { + "total": 31, + "by_people": 24, + "by_bots": 7, + "people": [ + { + "login": "Svilen-Stefanov", + "kind": "person", + "runs": 12 + }, + { + "login": "ivanmilevtues", + "kind": "person", + "runs": 9 + }, + { + "login": "dependabot[bot]", + "kind": "bot", + "runs": 7 + }, + { + "login": "brovatten", + "kind": "person", + "runs": 2 + }, + { + "login": "tsvetan-codes", + "kind": "person", + "runs": 1 + } + ] + }, + "seats": { + "month": "2026-09", + "active": 4, + "limit": 10 + } +} diff --git a/tests/contracts/me.schema.json b/tests/contracts/me.schema.json index 4a6d50a..89dfad8 100644 --- a/tests/contracts/me.schema.json +++ b/tests/contracts/me.schema.json @@ -214,6 +214,10 @@ "type": "boolean", "description": "true when this organisation's plan covers the signed-in person" }, + "admin": { + "type": "boolean", + "description": "true when the signed-in person is an admin of this GitHub organisation (the organisation view, GET /workspaces/{workspace}/usage, also needs a Team or Enterprise plan)" + }, "members_permission": { "type": "boolean" }, @@ -233,6 +237,7 @@ "login", "plan", "covered", + "admin", "members_permission", "bot_runs" ], diff --git a/tests/contracts/run-start.request.schema.json b/tests/contracts/run-start.request.schema.json index cc2d1ad..d8921b4 100644 --- a/tests/contracts/run-start.request.schema.json +++ b/tests/contracts/run-start.request.schema.json @@ -45,6 +45,11 @@ "minimum": 1, "description": "Action: the depth of the default-branch baseline, when one exists" }, + "pull_request": { + "type": "integer", + "minimum": 1, + "description": "Action: the pull request a comment-triggered run (issue_comment, or any run not on refs/pull//merge that is not a sync) is for. The run then counts once a week per pull request, charged to the commenter, when our GitHub App confirms the pull request is in the repository; otherwise it counts on its own run. Honour system" + }, "client": { "type": "object", "properties": { diff --git a/tests/contracts/usage.schema.json b/tests/contracts/usage.schema.json new file mode 100644 index 0000000..db7ca8e --- /dev/null +++ b/tests/contracts/usage.schema.json @@ -0,0 +1,213 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://codeboarding.org/schemas/licensing/v1/usage.schema.json", + "title": "Answer of GET /me/usage: what this ISO week's runs and private reviews counted, newest first", + "type": "object", + "properties": { + "period": { + "type": "string", + "pattern": "^[0-9]{4}-W[0-9]{2}$" + }, + "resets_at": { + "type": "string", + "format": "date-time" + }, + "runs": { + "type": "object", + "properties": { + "used": { + "type": "integer", + "minimum": 0, + "description": "The same count as /me's runs meter: counted items plus runs in flight" + }, + "limit": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "by_you": { + "type": "integer", + "minimum": 0, + "description": "used minus by_bots" + }, + "by_bots": { + "type": "integer", + "minimum": 0, + "description": "Items opened by a bot in the person's own repositories" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/run_item" + } + } + }, + "required": [ + "used", + "limit", + "by_you", + "by_bots", + "items" + ], + "additionalProperties": false + }, + "reviews": { + "type": "object", + "properties": { + "used": { + "type": "integer", + "minimum": 0 + }, + "limit": { + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "items": { + "type": "array", + "items": { + "$ref": "#/$defs/review_item" + } + } + }, + "required": [ + "used", + "limit", + "items" + ], + "additionalProperties": false + } + }, + "required": [ + "period", + "resets_at", + "runs", + "reviews" + ], + "additionalProperties": false, + "$defs": { + "run_item": { + "type": "object", + "description": "One counted pull request (or workflow run) or VS Code repository. Fields other than key, surface and updates are null for an item counted before attribution was kept", + "properties": { + "key": { + "type": "string", + "description": "github:#pr, github:#run, or vscode:" + }, + "surface": { + "enum": [ + "github", + "vscode" + ] + }, + "repository": { + "type": [ + "string", + "null" + ], + "description": "owner/name for GitHub; for VS Code the client's repository.name, display only" + }, + "pr": { + "type": [ + "integer", + "null" + ], + "minimum": 1 + }, + "by": { + "anyOf": [ + { + "type": "object", + "properties": { + "kind": { + "enum": [ + "person", + "bot" + ] + }, + "login": { + "type": "string" + } + }, + "required": [ + "kind", + "login" + ], + "additionalProperties": false + }, + { + "type": "null" + } + ], + "description": "Who opened it: the GitHub actor (the commenter for a comment-triggered run), or the signed-in account for VS Code" + }, + "first_run_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "When the run that counted it started" + }, + "updates": { + "type": "integer", + "minimum": 0, + "description": "Later runs of the same item this week, which did not count again" + } + }, + "required": [ + "key", + "surface", + "repository", + "pr", + "by", + "first_run_at", + "updates" + ], + "additionalProperties": false + }, + "review_item": { + "type": "object", + "description": "One private map opened this week. repository, pr and opened_at are null for one opened before they were kept", + "properties": { + "key": { + "type": "string", + "description": "github:#pr, or github:#run" + }, + "repository": { + "type": [ + "string", + "null" + ], + "description": "owner/name" + }, + "pr": { + "type": [ + "integer", + "null" + ], + "minimum": 1 + }, + "opened_at": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "When it was first opened this week" + } + }, + "required": [ + "key", + "repository", + "pr", + "opened_at" + ], + "additionalProperties": false + } + } +} diff --git a/tests/contracts/workspace-usage.schema.json b/tests/contracts/workspace-usage.schema.json new file mode 100644 index 0000000..782e1c1 --- /dev/null +++ b/tests/contracts/workspace-usage.schema.json @@ -0,0 +1,120 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://codeboarding.org/schemas/licensing/v1/workspace-usage.schema.json", + "title": "Answer of GET /workspaces/{workspace}/usage: an organisation's week and month, for its admins while it has a Team or Enterprise plan (403 otherwise)", + "type": "object", + "properties": { + "workspace": { + "type": "string", + "pattern": "^workspace:github:[0-9]+$" + }, + "login": { + "type": "string" + }, + "plan": { + "enum": [ + "team", + "enterprise" + ] + }, + "period": { + "type": "string", + "pattern": "^[0-9]{4}-W[0-9]{2}$" + }, + "resets_at": { + "type": "string", + "format": "date-time" + }, + "runs": { + "type": "object", + "description": "This week's charged runs in the organisation's repositories: each pull request (or other run) counts once, whoever pays for it", + "properties": { + "total": { + "type": "integer", + "minimum": 0 + }, + "by_people": { + "type": "integer", + "minimum": 0 + }, + "by_bots": { + "type": "integer", + "minimum": 0 + }, + "people": { + "type": "array", + "description": "Most runs first", + "items": { + "type": "object", + "properties": { + "login": { + "type": "string" + }, + "kind": { + "enum": [ + "person", + "bot" + ] + }, + "runs": { + "type": "integer", + "minimum": 1 + } + }, + "required": [ + "login", + "kind", + "runs" + ], + "additionalProperties": false + } + } + }, + "required": [ + "total", + "by_people", + "by_bots", + "people" + ], + "additionalProperties": false + }, + "seats": { + "type": "object", + "description": "This billing month's active developers of the plan's subject (the organisation, or its Enterprise company)", + "properties": { + "month": { + "type": "string", + "pattern": "^[0-9]{4}-[0-9]{2}$" + }, + "active": { + "type": "integer", + "minimum": 0 + }, + "limit": { + "type": [ + "integer", + "null" + ], + "minimum": 1, + "description": "The plan's seats (Team's default 10); null for an Enterprise contract without seats" + } + }, + "required": [ + "month", + "active", + "limit" + ], + "additionalProperties": false + } + }, + "required": [ + "workspace", + "login", + "plan", + "period", + "resets_at", + "runs", + "seats" + ], + "additionalProperties": false +} From 8a24dce8a239d0dd42972a4ef935ed6591b13461 Mon Sep 17 00:00:00 2001 From: Svilen Stefanov Date: Thu, 24 Sep 2026 22:29:15 +0200 Subject: [PATCH 2/2] feat: name the pull request of a /codeboarding comment run in the run check An issue_comment run's OIDC token carries no pull request, so the proxy counted every /codeboarding comment as its own run. The preflight now sends pull_request, the number guard.sh resolved, whenever the run is for a pull request but GitHub's ref is not refs/pull//merge. The proxy then keys the run on that pull request (once a week, charged to the commenter) when our GitHub App confirms it. A pull_request run never sends it: its token already names the pull request. Co-Authored-By: Claude Opus 5.5 (1M context) --- action.yml | 1 + scripts/action/run_meter.py | 9 ++++++++- tests/test_run_meter.py | 14 ++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 2b08568..43358d4 100644 --- a/action.yml +++ b/action.yml @@ -359,6 +359,7 @@ runs: env: DEPTH_CAP: ${{ inputs.depth_cap }} CHECKOUT_DIR: ${{ github.workspace }}/.codeboarding-target + PR_NUMBER: ${{ steps.guard.outputs.pr_number }} run: python3 "$GITHUB_ACTION_PATH/scripts/action/run_meter.py" start - name: Setup Java for CodeBoarding diff --git a/scripts/action/run_meter.py b/scripts/action/run_meter.py index 6826142..3556944 100755 --- a/scripts/action/run_meter.py +++ b/scripts/action/run_meter.py @@ -71,12 +71,19 @@ def baseline_depth(checkout: Path) -> int | None: def start_request(environ: dict[str, str], depth: int, tier: str) -> dict: manifest = json.loads((ACTION_ROOT / ".release-please-manifest.json").read_text(encoding="utf-8")) - return { + body = { "depth": depth, "credential": "hosted" if tier in ("hosted", "license") else "own_key", "baseline_depth": baseline_depth(Path(environ.get("CHECKOUT_DIR", ""))), "client": {"surface": "action", "version": manifest["."]}, } + # A /codeboarding comment's OIDC token names no pull request, so the proxy is told which. + pull_request = environ.get("PR_NUMBER", "") + if re.fullmatch(r"[1-9][0-9]*", pull_request) and not re.fullmatch( + r"refs/pull/[0-9]+/merge", environ.get("GITHUB_REF", "") + ): + body["pull_request"] = int(pull_request) + return body def start(environ: dict[str, str]) -> tuple[dict[str, str], int]: diff --git a/tests/test_run_meter.py b/tests/test_run_meter.py index a7ea208..140d0ce 100644 --- a/tests/test_run_meter.py +++ b/tests/test_run_meter.py @@ -144,6 +144,20 @@ def test_an_unknown_baseline_depth_is_sent_as_null(self) -> None: _, requests, _ = self._start(example("run-start.allowed.json")) self.assertIsNone(requests[0][2]["baseline_depth"]) + @NEEDS_JSONSCHEMA + def test_a_comment_run_names_its_pull_request(self) -> None: + """An issue_comment run's OIDC token carries no pull request, so the proxy keys on this.""" + _, requests, _ = self._start(example("run-start.allowed.json"), PR_NUMBER="482", GITHUB_REF="refs/heads/main") + body = requests[0][2] + self.assertEqual(body["pull_request"], 482) + self.assertEqual(validate(body, "run-start.request.schema.json"), []) + + def test_a_pull_request_run_leaves_its_number_to_the_token(self) -> None: + _, requests, _ = self._start( + example("run-start.allowed.json"), PR_NUMBER="482", GITHUB_REF="refs/pull/482/merge" + ) + self.assertNotIn("pull_request", requests[0][2]) + def test_a_staged_licence_rides_in_the_bearer_on_the_license_and_own_key_tiers(self) -> None: """Otherwise a licence holder on their own key reads as Free at the proxy.""" _, bare, _ = self._start(example("run-start.allowed.json"), "byok")