diff --git a/openspec/changes/github-provider-code-search/design.md b/openspec/changes/archive/2026-10-15-github-provider-code-search/design.md similarity index 100% rename from openspec/changes/github-provider-code-search/design.md rename to openspec/changes/archive/2026-10-15-github-provider-code-search/design.md diff --git a/openspec/changes/github-provider-code-search/proposal.md b/openspec/changes/archive/2026-10-15-github-provider-code-search/proposal.md similarity index 100% rename from openspec/changes/github-provider-code-search/proposal.md rename to openspec/changes/archive/2026-10-15-github-provider-code-search/proposal.md diff --git a/openspec/changes/github-provider-code-search/specs/credential-broker/spec.md b/openspec/changes/archive/2026-10-15-github-provider-code-search/specs/credential-broker/spec.md similarity index 91% rename from openspec/changes/github-provider-code-search/specs/credential-broker/spec.md rename to openspec/changes/archive/2026-10-15-github-provider-code-search/specs/credential-broker/spec.md index 0c18185b86..9b37223789 100644 --- a/openspec/changes/github-provider-code-search/specs/credential-broker/spec.md +++ b/openspec/changes/archive/2026-10-15-github-provider-code-search/specs/credential-broker/spec.md @@ -31,5 +31,5 @@ of `/search/code`. The per-file read stays covered by the existing - **WHEN** a brokered call requests `POST`, `PUT` or `DELETE` on `/search/code`, or `GET /search/commits`, `GET /search/users`, `GET /search/code/extra` or `GET /search/codes` -- **THEN** the broker refuses it with `no allow-rule matches` and makes no - outbound call +- **THEN** the broker refuses it with the static 403 (`Request not permitted`; + the reason is logged, never returned) and makes no outbound call diff --git a/openspec/changes/github-provider-code-search/tasks.md b/openspec/changes/archive/2026-10-15-github-provider-code-search/tasks.md similarity index 78% rename from openspec/changes/github-provider-code-search/tasks.md rename to openspec/changes/archive/2026-10-15-github-provider-code-search/tasks.md index 666594903d..3ff319f95c 100644 --- a/openspec/changes/github-provider-code-search/tasks.md +++ b/openspec/changes/archive/2026-10-15-github-provider-code-search/tasks.md @@ -8,4 +8,4 @@ - [x] 2.1 `tests/Unit/Service/Credential/GithubCodeSearchRuleTest.php`: drives `CredentialBrokerService::request()` with the shipped catalogue. `GET /search/code` with and without a query string, and `GET /repos/{owner}/{repo}/contents/publiccode.yml`, reach the client host-locked to `api.github.com` with the token header. POST/PUT/DELETE on `/search/code`, `GET /search/commits`, `GET /search/users`, `GET /search/code/extra` and `GET /search/codes` are refused with no outbound call. Fails without the rule (checked by removing it: 3 of 11 red). - [x] 2.2 Raise the rule-count pin in `DoffinProviderTest` from 18 to 19. - [x] 2.3 Live on the :8096 stack: a `github` credential, brokered `GET /search/code` reaches the outbound call (no allow-rule refusal), `POST /search/code` and `GET /search/commits` are refused. -- [ ] 2.4 Authenticated harvest against real GitHub with Ruben's token (coordinator; no token exists yet). +- [x] 2.4 Authenticated harvest against real GitHub (coordinator). (verified: WOO-585 rig against real github.com, brokered through the `github` credential `github-publiccode` holding Wilco's own GitHub token, 24 of 24 shards, 698 components on 2026-10-01 and 902 on 2026-10-13 (WOO-585 test plan, scenario 4)) diff --git a/openspec/specs/credential-broker/spec.md b/openspec/specs/credential-broker/spec.md index 868e2367fd..0ba1c2b6b7 100644 --- a/openspec/specs/credential-broker/spec.md +++ b/openspec/specs/credential-broker/spec.md @@ -520,3 +520,37 @@ throw); the app's OR app-key onboarding and the broker SHALL continue unchanged. - **WHEN** the onboarding hook runs while Doriath is absent, disabled, or its `ApplicationService` is unloadable - **THEN** it logs/outputs a warning and completes without error - **AND** the app's OpenRegister app-key onboarding and the credential broker continue to operate unchanged + +### Requirement: GitHub code search allow-rule + +The provider catalogue's `github` entry SHALL permit `GET /search/code` so a +caller can find files by name across every repository the token can see. The +rule SHALL match the path exactly (after the broker strips the query string), +SHALL be GET only, and SHALL NOT grant any other search endpoint or any sub-path +of `/search/code`. The per-file read stays covered by the existing +`GET /repos/*` rule; no additional contents rule is added. + +#### Scenario: Code search with a query and a page is allowed + +- **WHEN** a brokered call for a `github` credential requests + `GET /search/code?q=filename%3Apubliccode.yml+path%3A%2F&per_page=100&page=3` +- **THEN** the query string is stripped for rule matching and the + `GET /search/code` rule matches +- **AND** the outbound URL is + `https://api.github.com/search/code?q=filename%3Apubliccode.yml+path%3A%2F&per_page=100&page=3` + with the broker-injected `Authorization` header + +#### Scenario: The per-file contents read stays allowed + +- **WHEN** a brokered call requests + `GET /repos/ConductionNL/opencatalogi/contents/publiccode.yml?ref=main` +- **THEN** the existing `GET /repos/*` rule matches and the call proceeds + host-locked to `api.github.com` + +#### Scenario: Writes and other searches stay refused + +- **WHEN** a brokered call requests `POST`, `PUT` or `DELETE` on `/search/code`, + or `GET /search/commits`, `GET /search/users`, `GET /search/code/extra` or + `GET /search/codes` +- **THEN** the broker refuses it with the static 403 (`Request not permitted`; + the reason is logged, never returned) and makes no outbound call diff --git a/tests/Unit/Service/Credential/GithubCodeSearchRuleTest.php b/tests/Unit/Service/Credential/GithubCodeSearchRuleTest.php index c30d5ab131..0f695ba7f0 100644 --- a/tests/Unit/Service/Credential/GithubCodeSearchRuleTest.php +++ b/tests/Unit/Service/Credential/GithubCodeSearchRuleTest.php @@ -21,7 +21,7 @@ * * @link https://conduction.nl * - * @spec openspec/changes/github-provider-code-search/specs/credential-broker/spec.md#requirement-github-code-search-allow-rule + * @spec openspec/specs/credential-broker/spec.md#requirement-github-code-search-allow-rule */ declare(strict_types=1);