specguard-mcp 0.1.10 → 0.1.12
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.
- package/README.md +91 -7
- package/dist/src/support/specguard-api.d.ts +17 -0
- package/dist/src/support/specguard-api.js +19 -0
- package/dist/src/support/specguard-api.js.map +1 -1
- package/dist/src/tools/index.d.ts +24 -0
- package/dist/src/tools/index.js +30 -0
- package/dist/src/tools/index.js.map +1 -1
- package/dist/src/tools/list-repositories.d.ts +39 -10
- package/dist/src/tools/list-repositories.js +115 -19
- package/dist/src/tools/list-repositories.js.map +1 -1
- package/dist/src/tools/list-repository-agent-keys-presented-revoked.d.ts +39 -0
- package/dist/src/tools/list-repository-agent-keys-presented-revoked.js +89 -0
- package/dist/src/tools/list-repository-agent-keys-presented-revoked.js.map +1 -0
- package/dist/src/tools/list-repository-agent-keys.d.ts +38 -0
- package/dist/src/tools/list-repository-agent-keys.js +86 -0
- package/dist/src/tools/list-repository-agent-keys.js.map +1 -0
- package/dist/src/tools/registrable-repositories.d.ts +7 -2
- package/dist/src/tools/registrable-repositories.js +7 -2
- package/dist/src/tools/registrable-repositories.js.map +1 -1
- package/dist/src/tools/revoke-repository-agent-key.d.ts +45 -0
- package/dist/src/tools/revoke-repository-agent-key.js +104 -0
- package/dist/src/tools/revoke-repository-agent-key.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ refuses to boot and takes the tools that needed no configuration down with it.
|
|
|
34
34
|
| --- | --- | --- | --- |
|
|
35
35
|
| `SPECGUARD_ENDPOINT` | `get_repository_overview`, `list_repositories`, `add_repository`, `registrable_repositories` | — | your SpecGuard instance's root URL, **including the scheme** — e.g. `https://specguard.example.com`, or `http://localhost:3000`. A value with no scheme is refused by name (`SPECGUARD_ENDPOINT is not a usable URL: "sg.example.com"`) rather than surfacing later as an opaque failure. `SPECGUARD_URL` is accepted as an alias, and is the name every message uses when it is the one you set. A blank value counts as unset, so leaving `SPECGUARD_ENDPOINT` empty in a templated config falls through to `SPECGUARD_URL` instead of suppressing it |
|
|
36
36
|
| `SPECGUARD_API_KEY` | `get_repository_overview` | — | an agent/CI API key (`sgk_…`) issued by that deployment |
|
|
37
|
-
| `SPECGUARD_USER_API_KEY` | `list_repositories`, `add_repository`, `registrable_repositories`, `remove_repository`, `create_repository_api_key`, `revoke_repository_api_key`, `list_repository_members`, `add_repository_member`, `update_repository_member_permissions`, `remove_repository_member`, `rename_repository` | — | a **user** API key (`sgu_…`), minted from that deployment's account page. A different credential from the one above, not a second place to put the same value: SpecGuard decides which of them a request may use from the token's prefix, before it reads anything, and answers `401` for the other one. Set whichever your tools need — both, if you use both |
|
|
37
|
+
| `SPECGUARD_USER_API_KEY` | `list_repositories`, `add_repository`, `registrable_repositories`, `remove_repository`, `create_repository_api_key`, `revoke_repository_api_key`, `list_repository_agent_keys`, `revoke_repository_agent_key`, `list_repository_agent_keys_presented_revoked`, `list_repository_members`, `add_repository_member`, `update_repository_member_permissions`, `remove_repository_member`, `rename_repository` | — | a **user** API key (`sgu_…`), minted from that deployment's account page. A different credential from the one above, not a second place to put the same value: SpecGuard decides which of them a request may use from the token's prefix, before it reads anything, and answers `401` for the other one. Set whichever your tools need — both, if you use both |
|
|
38
38
|
| `SPECGUARD_LINT_COMMAND` | `lint_intent_annotations` | `specguard-lint` | the command that runs the linter. Most Ruby projects need `bundle exec specguard-lint` |
|
|
39
39
|
| `SPECGUARD_TIMEOUT_MS` | HTTP tools | `30000` | how long a call to SpecGuard may take |
|
|
40
40
|
|
|
@@ -331,14 +331,23 @@ ask about*, which is the one question no other tool here can answer. `get_reposi
|
|
|
331
331
|
no repository because its `sgk_…` key **is** the repository, so without this an agent can only report
|
|
332
332
|
on a repository somebody already named for it.
|
|
333
333
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
334
|
+
The credential decides which repositories are *in* the answer (owned, plus shared with them
|
|
335
|
+
through a membership); the three optional asks below narrow **within** that set — never around it.
|
|
336
|
+
The endpoint has served them since SpecGuard's SPGD-940 (`ef6236d`), composed through the same
|
|
337
|
+
`RepositoryNarrowing` concern the web grid reads, and this tool forwards them rather than
|
|
338
|
+
re-deriving them. A repository the person neither owns nor was given access to never enters the
|
|
339
|
+
response, so no ask can filter it *in* either. A blank value is no ask: passing an empty string
|
|
340
|
+
and omitting the argument make the identical request.
|
|
341
|
+
|
|
342
|
+
| argument | |
|
|
343
|
+
| --- | --- |
|
|
344
|
+
| `q` | keep only repositories whose `full_name` (`org/repo`) contains this substring, case-insensitively. A plain substring, not a pattern — the LIKE wildcards `%`/`_` are escaped server-side, so `org/my_repo` matches itself. A match-less ask is an empty list, not an error |
|
|
345
|
+
| `role` | `"owned"` or `"shared"` — one half of the list's mix: the repositories this person owns, or the ones shared with them. Mind the spelling: the *ask* values are `owned`/`shared`, while each entry's `role` field reads `owner`/`member` — `role: "owner"` is not a valid ask and settles to no ask (full list, no error) |
|
|
346
|
+
| `sort` | `"stale"` — re-order stalest-first: repositories CI has never ingested a run for first, then least-recently-ingested, with `full_name` breaking ties so two calls agree element for element. The same entries, a different order; the default order stays `full_name` ascending |
|
|
339
347
|
|
|
340
348
|
The body comes back as SpecGuard serves it — `{"repositories": […]}`, each entry carrying `id`,
|
|
341
|
-
`full_name`, `name`, `registered_at` and `role`, ordered by `full_name` ascending
|
|
349
|
+
`full_name`, `name`, `registered_at` and `role`, ordered by `full_name` ascending unless `sort`
|
|
350
|
+
asks otherwise. The first four are
|
|
342
351
|
deliberately the same four fields, under the same names, that `get_repository_overview` serves in its
|
|
343
352
|
own `repository` block, so a client that reads one reads the other. `role` is `owner` or `member`:
|
|
344
353
|
the list mixes repositories this person owns with repositories somebody shared with them, and nothing
|
|
@@ -539,6 +548,81 @@ means the key is revoked.
|
|
|
539
548
|
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
|
|
540
549
|
`add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
|
|
541
550
|
|
|
551
|
+
### `list_repository_agent_keys`
|
|
552
|
+
|
|
553
|
+
Lists the agent keys (`sga_…` keys) covering a SpecGuard repository — the keys minted for people
|
|
554
|
+
or automation principals from the /account page, each covering one or more repositories. One row
|
|
555
|
+
per live key: `id`, `name`, `owner`, `token_hint`, `repository_count` (how many repositories the
|
|
556
|
+
key's grant covers — the blast radius), `permissions` and `created_at`.
|
|
557
|
+
|
|
558
|
+
| argument | |
|
|
559
|
+
| --- | --- |
|
|
560
|
+
| `repository_id` | the repository whose agent keys to list — its numeric `id`, as `add_repository` returns and `list_repositories` reports, not the `org/repo` handle |
|
|
561
|
+
|
|
562
|
+
**The `id` here is the only way to name an agent key on this bridge.** Agent keys have no mint
|
|
563
|
+
tool — the platform mints them web-only at /account, deliberately — so unlike `sgk_` keys there is
|
|
564
|
+
no create response to read an id from. List first, then `revoke_repository_agent_key`. Revoked keys
|
|
565
|
+
leave this listing (a retained revoked row is not a credential); whether a dead token is still
|
|
566
|
+
arriving is `list_repository_agent_keys_presented_revoked`'s question.
|
|
567
|
+
|
|
568
|
+
`token_hint` is a hint, never the token — the plaintext existed for exactly one response at mint
|
|
569
|
+
time and nothing persisted it. Authorization is the `keys_manage` capability; a caller without it
|
|
570
|
+
is refused `403` with SpecGuard's own sentence, verbatim.
|
|
571
|
+
|
|
572
|
+
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
|
|
573
|
+
`add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
|
|
574
|
+
|
|
575
|
+
### `revoke_repository_agent_key`
|
|
576
|
+
|
|
577
|
+
Revokes one agent key (`sga_…`) on a SpecGuard repository. **Irreversible, and the blast radius is
|
|
578
|
+
the key's whole stored set:** an agent key's grant (repository set + permission set) is stored once
|
|
579
|
+
at mint time, so this one call cuts the token on EVERY repository the key covers, not just
|
|
580
|
+
`repository_id`. Check `repository_count` on `list_repository_agent_keys` before cutting a
|
|
581
|
+
multi-repository key.
|
|
582
|
+
|
|
583
|
+
| argument | |
|
|
584
|
+
| --- | --- |
|
|
585
|
+
| `repository_id` | the repository whose key-administration scope the call is made under — its numeric `id`, as `add_repository` returns and `list_repositories` reports, not the `org/repo` handle. The cut itself lands on every repository in the key's stored set |
|
|
586
|
+
| `key_id` | the id of the agent key to revoke, as served by `list_repository_agent_keys` — the only id source, because agent keys have no mint tool on this bridge |
|
|
587
|
+
|
|
588
|
+
This endpoint answers **`200` with the disclosure body**, not the empty `204` the sgk_ sibling
|
|
589
|
+
`revoke_repository_api_key` serves: an `agent_key` block carrying `revoked_at`, `repository_count`
|
|
590
|
+
and the still-existing `repositories` names (plus `deleted_repository_count` when repositories
|
|
591
|
+
have been deleted since mint) — the API's substitute for the web confirm dialog, so the body
|
|
592
|
+
itself is the confirmation.
|
|
593
|
+
|
|
594
|
+
The `key_id` is scoped to `repository_id`: a key whose stored set does not cover this repository,
|
|
595
|
+
or one already revoked, is refused `404`, never a cross-repository cut. Authorization is the
|
|
596
|
+
`keys_manage` capability; a caller without it is refused `403` with SpecGuard's own sentence,
|
|
597
|
+
verbatim.
|
|
598
|
+
|
|
599
|
+
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
|
|
600
|
+
`add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
|
|
601
|
+
|
|
602
|
+
### `list_repository_agent_keys_presented_revoked`
|
|
603
|
+
|
|
604
|
+
Lists REVOKED agent keys whose token is still arriving at the deployment after revocation — the
|
|
605
|
+
verify half of offboarding. Run it after `revoke_repository_agent_key` to learn whether the dead
|
|
606
|
+
token is still being presented somewhere: each row carries `id`, `name`, `owner`, `token_hint`
|
|
607
|
+
(hunt this in whatever secret stores may still hold the dead token, and update them),
|
|
608
|
+
`repository_count`, `revoked_at` and `last_refused_at`.
|
|
609
|
+
|
|
610
|
+
| argument | |
|
|
611
|
+
| --- | --- |
|
|
612
|
+
| `repository_id` | the repository to triage — its numeric `id`, as `add_repository` returns and `list_repositories` reports, not the `org/repo` handle |
|
|
613
|
+
|
|
614
|
+
Two readings, stated plainly: **`last_refused_at` is the last observed presentation** — a recency,
|
|
615
|
+
never a claim that something is presenting the token right now. And **an empty
|
|
616
|
+
`{"agent_keys": []}` is an answer** — nothing is still arriving — not an absence of tracking; read
|
|
617
|
+
it as the offboarding having fully taken.
|
|
618
|
+
|
|
619
|
+
`token_hint` is a hint, never the token — the plaintext existed for exactly one response at mint
|
|
620
|
+
time and nothing persisted it. Authorization is the `keys_manage` capability; a caller without it
|
|
621
|
+
is refused `403` with SpecGuard's own sentence, verbatim.
|
|
622
|
+
|
|
623
|
+
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
|
|
624
|
+
`add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
|
|
625
|
+
|
|
542
626
|
### `list_repository_members`
|
|
543
627
|
|
|
544
628
|
Lists who has access to a SpecGuard repository: one row per member with their `id` (the
|
|
@@ -54,6 +54,23 @@ export declare function patchJson(api: ApiConfig, path: string, body: Record<str
|
|
|
54
54
|
* verbatim: only what happens to a SUCCESS body differs.
|
|
55
55
|
*/
|
|
56
56
|
export declare function deleteJson(api: ApiConfig, path: string, fetchImpl: typeof globalThis.fetch): Promise<string>;
|
|
57
|
+
/**
|
|
58
|
+
* `DELETE` that answers with a JSON body — the destructive verb's one non-empty
|
|
59
|
+
* answer, routed through `requestJson` rather than `deleteJson`'s raw-body
|
|
60
|
+
* handling.
|
|
61
|
+
*
|
|
62
|
+
* Every DELETE this surface served until now answered `204` with NO body — the
|
|
63
|
+
* reason `deleteJson` exists and returns raw text. The agent-key revoke
|
|
64
|
+
* (`DELETE /api/v1/repositories/:repository_id/agent_keys/:id`) answers `200`
|
|
65
|
+
* WITH a JSON disclosure body: the platform's substitute for the confirm dialog
|
|
66
|
+
* the web face shows, naming the full stored set the cut just landed on. The
|
|
67
|
+
* body is the point of the response, so this verb parses it — and re-deriving
|
|
68
|
+
* the status check and the not-JSON diagnosis here would be a third copy of the
|
|
69
|
+
* one check `requestJson` owns, which is exactly the argument `patchJson`'s
|
|
70
|
+
* header makes for its own 200-with-body case. `deleteJson` stays exported and
|
|
71
|
+
* byte-unchanged for the endpoints that legitimately answer empty.
|
|
72
|
+
*/
|
|
73
|
+
export declare function deleteJsonObject(api: ApiConfig, path: string, fetchImpl: typeof globalThis.fetch): Promise<Record<string, unknown>>;
|
|
57
74
|
/**
|
|
58
75
|
* `postJson`, narrowed exactly as `getJsonObject` narrows `getJson`.
|
|
59
76
|
*
|
|
@@ -77,6 +77,25 @@ export async function deleteJson(api, path, fetchImpl) {
|
|
|
77
77
|
throw describeFailure(response.status, body, api);
|
|
78
78
|
return body;
|
|
79
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* `DELETE` that answers with a JSON body — the destructive verb's one non-empty
|
|
82
|
+
* answer, routed through `requestJson` rather than `deleteJson`'s raw-body
|
|
83
|
+
* handling.
|
|
84
|
+
*
|
|
85
|
+
* Every DELETE this surface served until now answered `204` with NO body — the
|
|
86
|
+
* reason `deleteJson` exists and returns raw text. The agent-key revoke
|
|
87
|
+
* (`DELETE /api/v1/repositories/:repository_id/agent_keys/:id`) answers `200`
|
|
88
|
+
* WITH a JSON disclosure body: the platform's substitute for the confirm dialog
|
|
89
|
+
* the web face shows, naming the full stored set the cut just landed on. The
|
|
90
|
+
* body is the point of the response, so this verb parses it — and re-deriving
|
|
91
|
+
* the status check and the not-JSON diagnosis here would be a third copy of the
|
|
92
|
+
* one check `requestJson` owns, which is exactly the argument `patchJson`'s
|
|
93
|
+
* header makes for its own 200-with-body case. `deleteJson` stays exported and
|
|
94
|
+
* byte-unchanged for the endpoints that legitimately answer empty.
|
|
95
|
+
*/
|
|
96
|
+
export async function deleteJsonObject(api, path, fetchImpl) {
|
|
97
|
+
return asJsonObject(await requestJson(new URL(`${api.endpoint}${path}`), api, fetchImpl, { method: "DELETE" }));
|
|
98
|
+
}
|
|
80
99
|
/**
|
|
81
100
|
* `postJson`, narrowed exactly as `getJsonObject` narrows `getJson`.
|
|
82
101
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"specguard-api.js","sourceRoot":"","sources":["../../../src/support/specguard-api.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"specguard-api.js","sourceRoot":"","sources":["../../../src/support/specguard-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -146,6 +146,30 @@ import type { ToolDefinition } from "./types.js";
|
|
|
146
146
|
* may not rename it. Before this tool the bridge's only rename path was
|
|
147
147
|
* remove-and-re-register, which destroys every key, run and intent; this one
|
|
148
148
|
* keeps them.
|
|
149
|
+
*
|
|
150
|
+
* == The fourteenth through sixteenth: the agent-key family
|
|
151
|
+
*
|
|
152
|
+
* - `list_repository_agent_keys` and `revoke_repository_agent_key` wrap the
|
|
153
|
+
* inventory and revoke of `user_repository_agent_keys` (shipped: SPGD-1004,
|
|
154
|
+
* specguard `dfb9892`), and `list_repository_agent_keys_presented_revoked`
|
|
155
|
+
* wraps the still-presented triage over the same controller (shipped:
|
|
156
|
+
* SPGD-1023, specguard `533e77b`).
|
|
157
|
+
*
|
|
158
|
+
* The `sga_` noun's first bridge tools, and the gap they close is the one the
|
|
159
|
+
* platform controller's own header records: a `keys.manage` holder could
|
|
160
|
+
* already mint and revoke `sgk_` keys through this bridge but could not even
|
|
161
|
+
* LIST the agent keys covering a repository, so the offboarding arc — a
|
|
162
|
+
* departed member's agent key authenticating indefinitely — was not
|
|
163
|
+
* completable over the bridge at all. The family also forced the transport's
|
|
164
|
+
* third DELETE shape: this revoke answers `200` WITH a JSON disclosure body
|
|
165
|
+
* (the API's substitute for the web confirm dialog — the response that
|
|
166
|
+
* performs the cut also names every repository it landed on), so it routes
|
|
167
|
+
* through `deleteJsonObject` — `requestJson`'s parse — rather than
|
|
168
|
+
* `deleteJson`'s raw-body handling, which the empty-204 endpoints keep
|
|
169
|
+
* unchanged. And the id the revoke needs is learnable ONLY from the listing:
|
|
170
|
+
* minting is deliberately web-only at /account, so unlike the `sgk_` pair
|
|
171
|
+
* there is no create response to read an id from — the list and revoke
|
|
172
|
+
* descriptions say so rather than leaving it implicit.
|
|
149
173
|
*/
|
|
150
174
|
export declare const TOOLS: readonly ToolDefinition[];
|
|
151
175
|
export type { ToolContext, ToolDefinition, ToolResult } from "./types.js";
|
package/dist/src/tools/index.js
CHANGED
|
@@ -3,6 +3,8 @@ import addRepositoryMember from "./add-repository-member.js";
|
|
|
3
3
|
import createRepositoryApiKey from "./create-repository-api-key.js";
|
|
4
4
|
import lintIntentAnnotations from "./lint-intent-annotations.js";
|
|
5
5
|
import listRepositories from "./list-repositories.js";
|
|
6
|
+
import listRepositoryAgentKeys from "./list-repository-agent-keys.js";
|
|
7
|
+
import listRepositoryAgentKeysPresentedRevoked from "./list-repository-agent-keys-presented-revoked.js";
|
|
6
8
|
import listRepositoryMembers from "./list-repository-members.js";
|
|
7
9
|
import nearDuplicateClusters from "./near-duplicate-clusters.js";
|
|
8
10
|
import getRepositoryOverview from "./repository-overview.js";
|
|
@@ -10,6 +12,7 @@ import registrableRepositories from "./registrable-repositories.js";
|
|
|
10
12
|
import removeRepository from "./remove-repository.js";
|
|
11
13
|
import removeRepositoryMember from "./remove-repository-member.js";
|
|
12
14
|
import renameRepository from "./rename-repository.js";
|
|
15
|
+
import revokeRepositoryAgentKey from "./revoke-repository-agent-key.js";
|
|
13
16
|
import revokeRepositoryApiKey from "./revoke-repository-api-key.js";
|
|
14
17
|
import updateRepositoryMemberPermissions from "./update-repository-member-permissions.js";
|
|
15
18
|
/**
|
|
@@ -159,6 +162,30 @@ import updateRepositoryMemberPermissions from "./update-repository-member-permis
|
|
|
159
162
|
* may not rename it. Before this tool the bridge's only rename path was
|
|
160
163
|
* remove-and-re-register, which destroys every key, run and intent; this one
|
|
161
164
|
* keeps them.
|
|
165
|
+
*
|
|
166
|
+
* == The fourteenth through sixteenth: the agent-key family
|
|
167
|
+
*
|
|
168
|
+
* - `list_repository_agent_keys` and `revoke_repository_agent_key` wrap the
|
|
169
|
+
* inventory and revoke of `user_repository_agent_keys` (shipped: SPGD-1004,
|
|
170
|
+
* specguard `dfb9892`), and `list_repository_agent_keys_presented_revoked`
|
|
171
|
+
* wraps the still-presented triage over the same controller (shipped:
|
|
172
|
+
* SPGD-1023, specguard `533e77b`).
|
|
173
|
+
*
|
|
174
|
+
* The `sga_` noun's first bridge tools, and the gap they close is the one the
|
|
175
|
+
* platform controller's own header records: a `keys.manage` holder could
|
|
176
|
+
* already mint and revoke `sgk_` keys through this bridge but could not even
|
|
177
|
+
* LIST the agent keys covering a repository, so the offboarding arc — a
|
|
178
|
+
* departed member's agent key authenticating indefinitely — was not
|
|
179
|
+
* completable over the bridge at all. The family also forced the transport's
|
|
180
|
+
* third DELETE shape: this revoke answers `200` WITH a JSON disclosure body
|
|
181
|
+
* (the API's substitute for the web confirm dialog — the response that
|
|
182
|
+
* performs the cut also names every repository it landed on), so it routes
|
|
183
|
+
* through `deleteJsonObject` — `requestJson`'s parse — rather than
|
|
184
|
+
* `deleteJson`'s raw-body handling, which the empty-204 endpoints keep
|
|
185
|
+
* unchanged. And the id the revoke needs is learnable ONLY from the listing:
|
|
186
|
+
* minting is deliberately web-only at /account, so unlike the `sgk_` pair
|
|
187
|
+
* there is no create response to read an id from — the list and revoke
|
|
188
|
+
* descriptions say so rather than leaving it implicit.
|
|
162
189
|
*/
|
|
163
190
|
export const TOOLS = [
|
|
164
191
|
lintIntentAnnotations,
|
|
@@ -175,5 +202,8 @@ export const TOOLS = [
|
|
|
175
202
|
updateRepositoryMemberPermissions,
|
|
176
203
|
removeRepositoryMember,
|
|
177
204
|
renameRepository,
|
|
205
|
+
listRepositoryAgentKeys,
|
|
206
|
+
listRepositoryAgentKeysPresentedRevoked,
|
|
207
|
+
revokeRepositoryAgentKey,
|
|
178
208
|
];
|
|
179
209
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,mBAAmB,MAAM,4BAA4B,CAAC;AAC7D,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,qBAAqB,MAAM,0BAA0B,CAAC;AAC7D,OAAO,uBAAuB,MAAM,+BAA+B,CAAC;AACpE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,sBAAsB,MAAM,+BAA+B,CAAC;AACnE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,iCAAiC,MAAM,2CAA2C,CAAC;AAG1F
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,mBAAmB,MAAM,4BAA4B,CAAC;AAC7D,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,uBAAuB,MAAM,iCAAiC,CAAC;AACtE,OAAO,uCAAuC,MAAM,mDAAmD,CAAC;AACxG,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,qBAAqB,MAAM,0BAA0B,CAAC;AAC7D,OAAO,uBAAuB,MAAM,+BAA+B,CAAC;AACpE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,sBAAsB,MAAM,+BAA+B,CAAC;AACnE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,wBAAwB,MAAM,kCAAkC,CAAC;AACxE,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,iCAAiC,MAAM,2CAA2C,CAAC;AAG1F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2KG;AACH,MAAM,CAAC,MAAM,KAAK,GAA8B;IAC9C,qBAAqB;IACrB,qBAAqB;IACrB,gBAAgB;IAChB,aAAa;IACb,uBAAuB;IACvB,gBAAgB;IAChB,sBAAsB;IACtB,sBAAsB;IACtB,qBAAqB;IACrB,qBAAqB;IACrB,mBAAmB;IACnB,iCAAiC;IACjC,sBAAsB;IACtB,gBAAgB;IAChB,uBAAuB;IACvB,uCAAuC;IACvC,wBAAwB;CACzB,CAAC"}
|
|
@@ -39,14 +39,41 @@ import type { ToolDefinition } from "./types.js";
|
|
|
39
39
|
* makes a 401 or an unset variable name the one the OPERATOR of this tool has
|
|
40
40
|
* to go and fix. See `config.ts`.
|
|
41
41
|
*
|
|
42
|
-
* ==
|
|
42
|
+
* == The credential is the SCOPE, and the arguments narrow WITHIN it
|
|
43
43
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
44
|
+
* This file first shipped argument-less on a premise that has since rotted: it
|
|
45
|
+
* said "the endpoint takes no parameters", because the person the `sgu_` key
|
|
46
|
+
* speaks for was the entire scope of the answer. That stopped being true on
|
|
47
|
+
* 2026-09-05, when specguard `ef6236d` (SPGD-940, #941) grew
|
|
48
|
+
* `GET /api/v1/repositories` three narrowing asks through the shared
|
|
49
|
+
* `RepositoryNarrowing` concern — `?q=` (case-insensitive substring on
|
|
50
|
+
* `github_full_name`, with the LIKE wildcards escaped server-side, so a
|
|
51
|
+
* literal `org/my_repo` does not widen into a pattern match), `?role=owned`
|
|
52
|
+
* and `?role=shared` (the exact partition of the accessible set into owned and
|
|
53
|
+
* shared halves), and `?sort=stale` (never-ingested repositories first, then
|
|
54
|
+
* least-recently-ingested, `github_full_name` breaking ties so the order is
|
|
55
|
+
* deterministic). The concern's own comment says the endpoint reads them "for
|
|
56
|
+
* a machine" — and this bridge IS that machine, so they are forwarded here
|
|
57
|
+
* rather than re-invented.
|
|
58
|
+
*
|
|
59
|
+
* What has NOT changed is which side of the boundary the asks sit on.
|
|
60
|
+
* `Repository.accessible_by` — owned UNION shared-through-a-membership — is
|
|
61
|
+
* still the platform's read-side boundary, and the controller chains every ask
|
|
62
|
+
* onto the relation that boundary already admitted
|
|
63
|
+
* (`narrow_repositories(authorized_repositories, …)`): a repository the person
|
|
64
|
+
* neither owns nor is a member of never ENTERS the relation, so no argument
|
|
65
|
+
* here widens the answer — it can only narrow, or re-order, what the
|
|
66
|
+
* credential already admits. Out-of-vocabulary values are the server's to
|
|
67
|
+
* clamp, not ours: an unknown `role` or `sort` settles to the no-ask, never a
|
|
68
|
+
* 400, which is also why a value that reaches the wire is passed through
|
|
69
|
+
* verbatim rather than validated against a second vocabulary here.
|
|
70
|
+
*
|
|
71
|
+
* Blank is no ask, and so is undefined: `optionalString` returns `undefined`
|
|
72
|
+
* for a blank value and `getJson` omits an `undefined` query entry, so
|
|
73
|
+
* declining an ask and omitting the argument are the same wire request — the
|
|
74
|
+
* established spelling in this codebase (`repository-overview.ts` states it
|
|
75
|
+
* as build-don't-stringify), and the reason the no-argument request below is
|
|
76
|
+
* byte-identical to the one this tool made before it had arguments at all.
|
|
50
77
|
*
|
|
51
78
|
* == The response is passed through, not re-modelled
|
|
52
79
|
*
|
|
@@ -67,9 +94,11 @@ import type { ToolDefinition } from "./types.js";
|
|
|
67
94
|
*
|
|
68
95
|
* The order is `full_name` ascending, which the controller picks as the only
|
|
69
96
|
* column a client can page or diff against without SpecGuard promising an id
|
|
70
|
-
* ordering it has not designed
|
|
71
|
-
*
|
|
72
|
-
* order is
|
|
97
|
+
* ordering it has not designed — and `?sort=stale` re-sequences exactly that
|
|
98
|
+
* loaded set rather than issuing a different query, so the entries never
|
|
99
|
+
* change, only their order does. It is stated here for the same reason the
|
|
100
|
+
* other tool states its orders: a list whose order is a coincidence and a list
|
|
101
|
+
* whose order is a contract look identical in a response body.
|
|
73
102
|
*/
|
|
74
103
|
declare const listRepositories: ToolDefinition;
|
|
75
104
|
export default listRepositories;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getJsonObject, requireUserApiConfig } from "../support/specguard-api.js";
|
|
2
|
+
import { optionalString } from "./args.js";
|
|
2
3
|
/**
|
|
3
4
|
* `GET /api/v1/repositories` as a tool — shipped today in the platform
|
|
4
5
|
* (`specguard/config/routes.rb`, `Api::V1::UserRepositoriesController#index`).
|
|
@@ -39,14 +40,41 @@ import { getJsonObject, requireUserApiConfig } from "../support/specguard-api.js
|
|
|
39
40
|
* makes a 401 or an unset variable name the one the OPERATOR of this tool has
|
|
40
41
|
* to go and fix. See `config.ts`.
|
|
41
42
|
*
|
|
42
|
-
* ==
|
|
43
|
+
* == The credential is the SCOPE, and the arguments narrow WITHIN it
|
|
43
44
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
45
|
+
* This file first shipped argument-less on a premise that has since rotted: it
|
|
46
|
+
* said "the endpoint takes no parameters", because the person the `sgu_` key
|
|
47
|
+
* speaks for was the entire scope of the answer. That stopped being true on
|
|
48
|
+
* 2026-09-05, when specguard `ef6236d` (SPGD-940, #941) grew
|
|
49
|
+
* `GET /api/v1/repositories` three narrowing asks through the shared
|
|
50
|
+
* `RepositoryNarrowing` concern — `?q=` (case-insensitive substring on
|
|
51
|
+
* `github_full_name`, with the LIKE wildcards escaped server-side, so a
|
|
52
|
+
* literal `org/my_repo` does not widen into a pattern match), `?role=owned`
|
|
53
|
+
* and `?role=shared` (the exact partition of the accessible set into owned and
|
|
54
|
+
* shared halves), and `?sort=stale` (never-ingested repositories first, then
|
|
55
|
+
* least-recently-ingested, `github_full_name` breaking ties so the order is
|
|
56
|
+
* deterministic). The concern's own comment says the endpoint reads them "for
|
|
57
|
+
* a machine" — and this bridge IS that machine, so they are forwarded here
|
|
58
|
+
* rather than re-invented.
|
|
59
|
+
*
|
|
60
|
+
* What has NOT changed is which side of the boundary the asks sit on.
|
|
61
|
+
* `Repository.accessible_by` — owned UNION shared-through-a-membership — is
|
|
62
|
+
* still the platform's read-side boundary, and the controller chains every ask
|
|
63
|
+
* onto the relation that boundary already admitted
|
|
64
|
+
* (`narrow_repositories(authorized_repositories, …)`): a repository the person
|
|
65
|
+
* neither owns nor is a member of never ENTERS the relation, so no argument
|
|
66
|
+
* here widens the answer — it can only narrow, or re-order, what the
|
|
67
|
+
* credential already admits. Out-of-vocabulary values are the server's to
|
|
68
|
+
* clamp, not ours: an unknown `role` or `sort` settles to the no-ask, never a
|
|
69
|
+
* 400, which is also why a value that reaches the wire is passed through
|
|
70
|
+
* verbatim rather than validated against a second vocabulary here.
|
|
71
|
+
*
|
|
72
|
+
* Blank is no ask, and so is undefined: `optionalString` returns `undefined`
|
|
73
|
+
* for a blank value and `getJson` omits an `undefined` query entry, so
|
|
74
|
+
* declining an ask and omitting the argument are the same wire request — the
|
|
75
|
+
* established spelling in this codebase (`repository-overview.ts` states it
|
|
76
|
+
* as build-don't-stringify), and the reason the no-argument request below is
|
|
77
|
+
* byte-identical to the one this tool made before it had arguments at all.
|
|
50
78
|
*
|
|
51
79
|
* == The response is passed through, not re-modelled
|
|
52
80
|
*
|
|
@@ -67,9 +95,11 @@ import { getJsonObject, requireUserApiConfig } from "../support/specguard-api.js
|
|
|
67
95
|
*
|
|
68
96
|
* The order is `full_name` ascending, which the controller picks as the only
|
|
69
97
|
* column a client can page or diff against without SpecGuard promising an id
|
|
70
|
-
* ordering it has not designed
|
|
71
|
-
*
|
|
72
|
-
* order is
|
|
98
|
+
* ordering it has not designed — and `?sort=stale` re-sequences exactly that
|
|
99
|
+
* loaded set rather than issuing a different query, so the entries never
|
|
100
|
+
* change, only their order does. It is stated here for the same reason the
|
|
101
|
+
* other tool states its orders: a list whose order is a coincidence and a list
|
|
102
|
+
* whose order is a contract look identical in a response body.
|
|
73
103
|
*/
|
|
74
104
|
const listRepositories = {
|
|
75
105
|
name: "list_repositories",
|
|
@@ -82,7 +112,14 @@ const listRepositories = {
|
|
|
82
112
|
"`role` is `owner` or `member`: the list mixes repositories this person owns with " +
|
|
83
113
|
"repositories somebody shared with them, and nothing else distinguishes the two — read it " +
|
|
84
114
|
"before assuming a repository is yours to administer. " +
|
|
85
|
-
"
|
|
115
|
+
"Three optional asks narrow WITHIN that set — none of them can widen it — all optional, " +
|
|
116
|
+
"composable on one call: `q` (case-insensitive substring on `full_name`), " +
|
|
117
|
+
"`role: \"owned\"` or `\"shared\"` (one half of the owned/shared mix — note the ask is " +
|
|
118
|
+
"spelled `owned`, not the response field's `owner`), and `sort: \"stale\"` (repositories " +
|
|
119
|
+
"CI has never ingested a run for first, then least-recently-ingested, `full_name` " +
|
|
120
|
+
"breaking ties). Omit them all and the request is the plain full list. " +
|
|
121
|
+
"Ordered by `full_name` ascending unless `sort` asks otherwise, and stable across calls " +
|
|
122
|
+
"either way. " +
|
|
86
123
|
"The set is exactly what this person may see — a repository they neither own nor were given " +
|
|
87
124
|
"access to is absent rather than filtered, so an empty list means no access, never an error. " +
|
|
88
125
|
"Needs SPECGUARD_USER_API_KEY (an sgu_… key), which is a DIFFERENT credential from the " +
|
|
@@ -90,18 +127,77 @@ const listRepositories = {
|
|
|
90
127
|
"place.",
|
|
91
128
|
inputSchema: {
|
|
92
129
|
type: "object",
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
130
|
+
properties: {
|
|
131
|
+
q: {
|
|
132
|
+
type: "string",
|
|
133
|
+
description: "Keep only the repositories whose `github_full_name` (`org/repo`) CONTAINS this " +
|
|
134
|
+
"substring, case-insensitively — the same ask the deployment's web grid reads. " +
|
|
135
|
+
"A plain substring, not a pattern: the server matches with `ILIKE '%…%'` and escapes " +
|
|
136
|
+
"the LIKE wildcards (`%`, `_`, `\\`) first, so `org/my_repo` matches itself rather " +
|
|
137
|
+
"than widening into `my-repo` and `myxrepo`. " +
|
|
138
|
+
"It narrows the SAME set the plain call serves — a repository the credential does not " +
|
|
139
|
+
"admit never enters the response, so no `q` can make one appear — and an ask that " +
|
|
140
|
+
"matches nothing is an empty list with a 200, the same answer as having no access, " +
|
|
141
|
+
"not an error. " +
|
|
142
|
+
"Blank (or null) is no ask: the request is then byte-identical to omitting the " +
|
|
143
|
+
"argument.",
|
|
144
|
+
},
|
|
145
|
+
role: {
|
|
146
|
+
type: "string",
|
|
147
|
+
enum: ["owned", "shared"],
|
|
148
|
+
description: "Keep only ONE half of the list's mix: `owned` keeps the repositories this person " +
|
|
149
|
+
"owns, `shared` keeps the ones somebody shared with them. The two partition the " +
|
|
150
|
+
"accessible set exactly — a repository owned AND shared cannot exist by construction, " +
|
|
151
|
+
"so nothing is lost by asking for one half — and both chain onto the credential " +
|
|
152
|
+
"boundary, so neither half can be wider than the plain call's answer. " +
|
|
153
|
+
"THE ASK VALUES ARE SPELLED DIFFERENTLY FROM THE RESPONSE FIELD: an entry's `role` is " +
|
|
154
|
+
"`\"owner\"` or `\"member\"`, but the ask is `owned`/`shared` — send `role: " +
|
|
155
|
+
"\"owner\"` and you are not asking for anything. A client that honours this schema " +
|
|
156
|
+
"cannot send it (the enum refuses it before the call); a client that bypasses the " +
|
|
157
|
+
"schema gets the server's clamp, where any value outside `owned`/`shared` settles to " +
|
|
158
|
+
"the no-ask and the full list is served — never an error. " +
|
|
159
|
+
"Blank (or null) is no ask: byte-identical to omitting the argument.",
|
|
160
|
+
},
|
|
161
|
+
sort: {
|
|
162
|
+
type: "string",
|
|
163
|
+
enum: ["stale"],
|
|
164
|
+
description: "Re-order the list stalest-first. The default order is `full_name` ascending, which " +
|
|
165
|
+
"is stable across calls but says nothing about what needs attention; `stale` puts " +
|
|
166
|
+
"the repositories CI has NEVER ingested a run for FIRST (never-ingested is the " +
|
|
167
|
+
"stalest state on this list, not a zero), then least-recently-ingested, newest last, " +
|
|
168
|
+
"with `github_full_name` breaking ties so two calls with the same data agree element " +
|
|
169
|
+
"for element. " +
|
|
170
|
+
"It re-sequences the loaded set rather than issuing a different query: the same " +
|
|
171
|
+
"entries, a different order. `stale` is the only ordering the endpoint names — there " +
|
|
172
|
+
"is deliberately no word for the default, because omitting the argument already " +
|
|
173
|
+
"means it. " +
|
|
174
|
+
"Any other value a schema-bypassing client sends settles to the server's no-ask clamp " +
|
|
175
|
+
"(default order, no error); blank (or null) is no ask, byte-identical to omitting the " +
|
|
176
|
+
"argument.",
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
// Still CLOSED rather than open: `additionalProperties: false` is advertised
|
|
180
|
+
// in `tools/list`, so a client that honours the schema REJECTS an invented
|
|
96
181
|
// argument before the call is made. Nothing on this side refuses it —
|
|
97
|
-
// `server.ts` forwards `arguments` unvalidated
|
|
98
|
-
//
|
|
99
|
-
//
|
|
182
|
+
// `server.ts` forwards `arguments` unvalidated — so an open schema would
|
|
183
|
+
// have the argument silently dropped and the call answered as if it had
|
|
184
|
+
// been honoured. The enum vocabularies above are the server's own accepted
|
|
185
|
+
// values (`RepositoryNarrowing`'s ROLES and SORTS), not a second list this
|
|
186
|
+
// bridge keeps in step by hand.
|
|
100
187
|
additionalProperties: false,
|
|
101
188
|
},
|
|
102
|
-
async run(
|
|
189
|
+
async run(args, context) {
|
|
190
|
+
const q = optionalString(args["q"], "q");
|
|
191
|
+
const role = optionalString(args["role"], "role");
|
|
192
|
+
const sort = optionalString(args["sort"], "sort");
|
|
103
193
|
const api = requireUserApiConfig(context.config);
|
|
104
|
-
|
|
194
|
+
// Built, not stringified — the established rule for a query object
|
|
195
|
+
// (`repository-overview.ts`): `getJson` omits an `undefined` entry and sets
|
|
196
|
+
// everything else verbatim, so an ask declined (blank), omitted, or never
|
|
197
|
+
// defined all compose to the ONE request the caller meant, and with no asks
|
|
198
|
+
// at all the object is `{}` — the byte-identical request this tool made
|
|
199
|
+
// before it had arguments.
|
|
200
|
+
const listing = await getJsonObject(api, "/api/v1/repositories", { q, role, sort }, context.fetch);
|
|
105
201
|
return {
|
|
106
202
|
text: JSON.stringify(listing, null, 2),
|
|
107
203
|
structured: listing,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-repositories.js","sourceRoot":"","sources":["../../../src/tools/list-repositories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"list-repositories.js","sourceRoot":"","sources":["../../../src/tools/list-repositories.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ToolDefinition } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* `GET /api/v1/repositories/:repository_id/agent_keys/presented_revoked` as a
|
|
4
|
+
* tool — shipped in the platform (`specguard/config/routes.rb`,
|
|
5
|
+
* `Api::V1::UserRepositoryAgentKeysController#presented_revoked`, SPGD-1023,
|
|
6
|
+
* `533e77b`).
|
|
7
|
+
*
|
|
8
|
+
* == The verify half of the offboarding arc
|
|
9
|
+
*
|
|
10
|
+
* The listing and the revoke answer "what is live" and "cut this one"; neither
|
|
11
|
+
* can answer the question a revoker is left holding — "is the dead token still
|
|
12
|
+
* arriving?" — because both read LIVE rows only. The stamp this triage serves,
|
|
13
|
+
* `last_refused_at`, is written by the 401 failure path on RETAINED revoked
|
|
14
|
+
* rows, so it cannot ride a live row at all. This read is the bridge's only
|
|
15
|
+
* window onto it, behind the same `keys_manage` gate the other two actions
|
|
16
|
+
* answer to.
|
|
17
|
+
*
|
|
18
|
+
* == Two honesty clauses the description carries verbatim
|
|
19
|
+
*
|
|
20
|
+
* `last_refused_at` is the LAST observed presentation — a recency, never a
|
|
21
|
+
* present-tense claim that a client is presenting the token now. And an empty
|
|
22
|
+
* `{"agent_keys": []}` is an ANSWER — "no revoked key is still being
|
|
23
|
+
* presented" — not an absence of tracking; the endpoint serves the negative
|
|
24
|
+
* deliberately so the two are distinguishable. A tool that summarised an
|
|
25
|
+
* empty answer into a count of its own would erase exactly that distinction,
|
|
26
|
+
* which is why this one passes the body through.
|
|
27
|
+
*
|
|
28
|
+
* == Rows, pass-through
|
|
29
|
+
*
|
|
30
|
+
* One row per still-presented revoked key covering this repository: `id`,
|
|
31
|
+
* `name`, `owner`, `token_hint`, `repository_count` (the STORED set's size —
|
|
32
|
+
* the same blast-radius figure the revoke response discloses), `revoked_at`
|
|
33
|
+
* and `last_refused_at`. `token_hint` is what the remedy hunts for in the
|
|
34
|
+
* secret store — update whichever of them still holds the dead token — and it
|
|
35
|
+
* is never the token: the plaintext existed for exactly one response at mint
|
|
36
|
+
* time and nothing persisted it.
|
|
37
|
+
*/
|
|
38
|
+
declare const listRepositoryAgentKeysPresentedRevoked: ToolDefinition;
|
|
39
|
+
export default listRepositoryAgentKeysPresentedRevoked;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { getJsonObject, requireUserApiConfig } from "../support/specguard-api.js";
|
|
2
|
+
import { requireString } from "./args.js";
|
|
3
|
+
/**
|
|
4
|
+
* `GET /api/v1/repositories/:repository_id/agent_keys/presented_revoked` as a
|
|
5
|
+
* tool — shipped in the platform (`specguard/config/routes.rb`,
|
|
6
|
+
* `Api::V1::UserRepositoryAgentKeysController#presented_revoked`, SPGD-1023,
|
|
7
|
+
* `533e77b`).
|
|
8
|
+
*
|
|
9
|
+
* == The verify half of the offboarding arc
|
|
10
|
+
*
|
|
11
|
+
* The listing and the revoke answer "what is live" and "cut this one"; neither
|
|
12
|
+
* can answer the question a revoker is left holding — "is the dead token still
|
|
13
|
+
* arriving?" — because both read LIVE rows only. The stamp this triage serves,
|
|
14
|
+
* `last_refused_at`, is written by the 401 failure path on RETAINED revoked
|
|
15
|
+
* rows, so it cannot ride a live row at all. This read is the bridge's only
|
|
16
|
+
* window onto it, behind the same `keys_manage` gate the other two actions
|
|
17
|
+
* answer to.
|
|
18
|
+
*
|
|
19
|
+
* == Two honesty clauses the description carries verbatim
|
|
20
|
+
*
|
|
21
|
+
* `last_refused_at` is the LAST observed presentation — a recency, never a
|
|
22
|
+
* present-tense claim that a client is presenting the token now. And an empty
|
|
23
|
+
* `{"agent_keys": []}` is an ANSWER — "no revoked key is still being
|
|
24
|
+
* presented" — not an absence of tracking; the endpoint serves the negative
|
|
25
|
+
* deliberately so the two are distinguishable. A tool that summarised an
|
|
26
|
+
* empty answer into a count of its own would erase exactly that distinction,
|
|
27
|
+
* which is why this one passes the body through.
|
|
28
|
+
*
|
|
29
|
+
* == Rows, pass-through
|
|
30
|
+
*
|
|
31
|
+
* One row per still-presented revoked key covering this repository: `id`,
|
|
32
|
+
* `name`, `owner`, `token_hint`, `repository_count` (the STORED set's size —
|
|
33
|
+
* the same blast-radius figure the revoke response discloses), `revoked_at`
|
|
34
|
+
* and `last_refused_at`. `token_hint` is what the remedy hunts for in the
|
|
35
|
+
* secret store — update whichever of them still holds the dead token — and it
|
|
36
|
+
* is never the token: the plaintext existed for exactly one response at mint
|
|
37
|
+
* time and nothing persisted it.
|
|
38
|
+
*/
|
|
39
|
+
const listRepositoryAgentKeysPresentedRevoked = {
|
|
40
|
+
name: "list_repository_agent_keys_presented_revoked",
|
|
41
|
+
title: "List still-presented revoked agent keys",
|
|
42
|
+
description: "Lists REVOKED agent keys whose token is still arriving at the deployment after revocation — " +
|
|
43
|
+
"the verify half of offboarding: run it after `revoke_repository_agent_key` to learn whether " +
|
|
44
|
+
"the dead token is still being presented somewhere. Each row carries `id`, `name`, `owner`, " +
|
|
45
|
+
"`token_hint` (hunt THIS in whatever secret stores may still hold the dead token, and update " +
|
|
46
|
+
"them), `repository_count`, `revoked_at` and `last_refused_at`. " +
|
|
47
|
+
"`last_refused_at` is the LAST observed presentation — a recency, never a present-tense claim " +
|
|
48
|
+
"that something is presenting the token right now. " +
|
|
49
|
+
"An empty `{\"agent_keys\": []}` is an ANSWER — nothing is still arriving — not an absence of " +
|
|
50
|
+
"tracking; read it as the offboarding having fully taken. " +
|
|
51
|
+
"`token_hint` is a hint, never the token — the plaintext existed for exactly one response at " +
|
|
52
|
+
"mint time and nothing persisted it. " +
|
|
53
|
+
"Authorization is the `keys_manage` capability — a caller without it is refused 403 in " +
|
|
54
|
+
"SpecGuard's own words. " +
|
|
55
|
+
"Takes `repository_id` (the numeric id `list_repositories` reports, not the `org/repo` handle). " +
|
|
56
|
+
"Needs SPECGUARD_USER_API_KEY (an sgu_… key), the same credential the other key-administration " +
|
|
57
|
+
"tools read and a DIFFERENT one from the sgk_… repository key `get_repository_overview` uses.",
|
|
58
|
+
inputSchema: {
|
|
59
|
+
type: "object",
|
|
60
|
+
properties: {
|
|
61
|
+
repository_id: {
|
|
62
|
+
type: "string",
|
|
63
|
+
description: "The repository to triage — its numeric id, as `add_repository` returns and " +
|
|
64
|
+
"`list_repositories` reports, not the `org/repo` handle.",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
required: ["repository_id"],
|
|
68
|
+
// Closed for the reason every tool here states: `server.ts` forwards
|
|
69
|
+
// `arguments` unvalidated, so an open schema would let a misspelled argument
|
|
70
|
+
// be dropped silently.
|
|
71
|
+
additionalProperties: false,
|
|
72
|
+
},
|
|
73
|
+
async run(args, context) {
|
|
74
|
+
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
75
|
+
const api = requireUserApiConfig(context.config);
|
|
76
|
+
const body = await getJsonObject(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}/agent_keys/presented_revoked`, {}, context.fetch);
|
|
77
|
+
// Passed through unreshaped, the standing rule (`types.ts`: "A thin client
|
|
78
|
+
// that reshapes its upstream is not thin") — and the empty answer passes
|
|
79
|
+
// through with it: `{"agent_keys": []}` is the endpoint saying "nothing is
|
|
80
|
+
// still arriving", and a summary of it would erase the distinction between
|
|
81
|
+
// that answer and an absence of tracking.
|
|
82
|
+
return {
|
|
83
|
+
text: JSON.stringify(body, null, 2),
|
|
84
|
+
structured: body,
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
export default listRepositoryAgentKeysPresentedRevoked;
|
|
89
|
+
//# sourceMappingURL=list-repository-agent-keys-presented-revoked.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-repository-agent-keys-presented-revoked.js","sourceRoot":"","sources":["../../../src/tools/list-repository-agent-keys-presented-revoked.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,uCAAuC,GAAmB;IAC9D,IAAI,EAAE,8CAA8C;IACpD,KAAK,EAAE,yCAAyC;IAChD,WAAW,EACT,8FAA8F;QAC9F,8FAA8F;QAC9F,6FAA6F;QAC7F,8FAA8F;QAC9F,iEAAiE;QACjE,+FAA+F;QAC/F,oDAAoD;QACpD,+FAA+F;QAC/F,2DAA2D;QAC3D,8FAA8F;QAC9F,sCAAsC;QACtC,wFAAwF;QACxF,yBAAyB;QACzB,iGAAiG;QACjG,gGAAgG;QAChG,8FAA8F;IAChG,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,6EAA6E;oBAC7E,yDAAyD;aAC5D;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,CAAC;QAC3B,qEAAqE;QACrE,6EAA6E;QAC7E,uBAAuB;QACvB,oBAAoB,EAAE,KAAK;KAC5B;IAED,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO;QACrB,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC,CAAC;QAE3E,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,MAAM,IAAI,GAAG,MAAM,aAAa,CAC9B,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,+BAA+B,EACvF,EAAE,EACF,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,2EAA2E;QAC3E,yEAAyE;QACzE,2EAA2E;QAC3E,2EAA2E;QAC3E,0CAA0C;QAC1C,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACnC,UAAU,EAAE,IAAI;SACjB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,uCAAuC,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ToolDefinition } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* `GET /api/v1/repositories/:repository_id/agent_keys` as a tool — shipped in
|
|
4
|
+
* the platform (`specguard/config/routes.rb`,
|
|
5
|
+
* `Api::V1::UserRepositoryAgentKeysController#index`, SPGD-1004, `dfb9892`).
|
|
6
|
+
*
|
|
7
|
+
* == The id source is THIS listing, and only this listing
|
|
8
|
+
*
|
|
9
|
+
* Agent keys have no mint tool on this bridge — deliberately: the platform
|
|
10
|
+
* mints them web-only at /account (the controller header states the rule), so
|
|
11
|
+
* unlike `sgk_` keys there is no create response to read an id from. The `id`
|
|
12
|
+
* each row serves is therefore the ONLY way an agent can name an agent key to
|
|
13
|
+
* `revoke_repository_agent_key`, and the description says so rather than
|
|
14
|
+
* leaving it implicit — an agent that arrives needing to cut a key without
|
|
15
|
+
* having listed first has no fallback path.
|
|
16
|
+
*
|
|
17
|
+
* == Rows, pass-through
|
|
18
|
+
*
|
|
19
|
+
* The endpoint answers `{agent_keys: [...]}`, one row per LIVE key covering
|
|
20
|
+
* this repository: `id`, `name`, `owner`, `token_hint`, `repository_count`
|
|
21
|
+
* (the size of the key's stored set — the blast radius a revoke would land
|
|
22
|
+
* on), `permissions` (rendered the way the web panel renders it, "read only"
|
|
23
|
+
* for the minimal grant) and `created_at`. `token_hint` is a hint and never
|
|
24
|
+
* the token: the plaintext existed for exactly one response at mint time and
|
|
25
|
+
* nothing persisted it. Revoked rows leave the listing — a retained revoked
|
|
26
|
+
* row is not a credential — and the still-presented triage over those rows is
|
|
27
|
+
* `list_repository_agent_keys_presented_revoked`.
|
|
28
|
+
*
|
|
29
|
+
* == No client-side capability probing
|
|
30
|
+
*
|
|
31
|
+
* The server gates at `current_repository(:keys_manage)`, the same gate the
|
|
32
|
+
* `sgk_` key pair answers to: a caller who cannot administer this
|
|
33
|
+
* repository's keys is refused 403 in SpecGuard's own words, and a caller who
|
|
34
|
+
* cannot see the repository at all gets the nil-is-404 fork. This tool
|
|
35
|
+
* predicts neither; it reports what came back.
|
|
36
|
+
*/
|
|
37
|
+
declare const listRepositoryAgentKeys: ToolDefinition;
|
|
38
|
+
export default listRepositoryAgentKeys;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { getJsonObject, requireUserApiConfig } from "../support/specguard-api.js";
|
|
2
|
+
import { requireString } from "./args.js";
|
|
3
|
+
/**
|
|
4
|
+
* `GET /api/v1/repositories/:repository_id/agent_keys` as a tool — shipped in
|
|
5
|
+
* the platform (`specguard/config/routes.rb`,
|
|
6
|
+
* `Api::V1::UserRepositoryAgentKeysController#index`, SPGD-1004, `dfb9892`).
|
|
7
|
+
*
|
|
8
|
+
* == The id source is THIS listing, and only this listing
|
|
9
|
+
*
|
|
10
|
+
* Agent keys have no mint tool on this bridge — deliberately: the platform
|
|
11
|
+
* mints them web-only at /account (the controller header states the rule), so
|
|
12
|
+
* unlike `sgk_` keys there is no create response to read an id from. The `id`
|
|
13
|
+
* each row serves is therefore the ONLY way an agent can name an agent key to
|
|
14
|
+
* `revoke_repository_agent_key`, and the description says so rather than
|
|
15
|
+
* leaving it implicit — an agent that arrives needing to cut a key without
|
|
16
|
+
* having listed first has no fallback path.
|
|
17
|
+
*
|
|
18
|
+
* == Rows, pass-through
|
|
19
|
+
*
|
|
20
|
+
* The endpoint answers `{agent_keys: [...]}`, one row per LIVE key covering
|
|
21
|
+
* this repository: `id`, `name`, `owner`, `token_hint`, `repository_count`
|
|
22
|
+
* (the size of the key's stored set — the blast radius a revoke would land
|
|
23
|
+
* on), `permissions` (rendered the way the web panel renders it, "read only"
|
|
24
|
+
* for the minimal grant) and `created_at`. `token_hint` is a hint and never
|
|
25
|
+
* the token: the plaintext existed for exactly one response at mint time and
|
|
26
|
+
* nothing persisted it. Revoked rows leave the listing — a retained revoked
|
|
27
|
+
* row is not a credential — and the still-presented triage over those rows is
|
|
28
|
+
* `list_repository_agent_keys_presented_revoked`.
|
|
29
|
+
*
|
|
30
|
+
* == No client-side capability probing
|
|
31
|
+
*
|
|
32
|
+
* The server gates at `current_repository(:keys_manage)`, the same gate the
|
|
33
|
+
* `sgk_` key pair answers to: a caller who cannot administer this
|
|
34
|
+
* repository's keys is refused 403 in SpecGuard's own words, and a caller who
|
|
35
|
+
* cannot see the repository at all gets the nil-is-404 fork. This tool
|
|
36
|
+
* predicts neither; it reports what came back.
|
|
37
|
+
*/
|
|
38
|
+
const listRepositoryAgentKeys = {
|
|
39
|
+
name: "list_repository_agent_keys",
|
|
40
|
+
title: "List repository agent keys",
|
|
41
|
+
description: "Lists the agent keys (`sga_…` keys) covering a SpecGuard repository: one row per live key " +
|
|
42
|
+
"with its `id`, `name`, `owner`, `token_hint`, `repository_count` (how many repositories the " +
|
|
43
|
+
"key's grant covers — the blast radius), `permissions` and `created_at`. " +
|
|
44
|
+
"Agent keys have NO mint tool on this bridge — minting is deliberately web-only — so the `id` " +
|
|
45
|
+
"this listing serves is the ONLY way to name a key to `revoke_repository_agent_key`: list " +
|
|
46
|
+
"first, then revoke. " +
|
|
47
|
+
"Revoked keys leave this listing (a retained revoked row is not a credential); whether a dead " +
|
|
48
|
+
"token is still arriving is `list_repository_agent_keys_presented_revoked`'s question. " +
|
|
49
|
+
"`token_hint` is a hint, never the token — the plaintext existed for exactly one response at " +
|
|
50
|
+
"mint time and nothing persisted it. " +
|
|
51
|
+
"Authorization is the `keys_manage` capability — a caller without it is refused 403 in " +
|
|
52
|
+
"SpecGuard's own words. " +
|
|
53
|
+
"Takes `repository_id` (the numeric id `list_repositories` reports, not the `org/repo` handle). " +
|
|
54
|
+
"Needs SPECGUARD_USER_API_KEY (an sgu_… key), the same credential the other key-administration " +
|
|
55
|
+
"tools read and a DIFFERENT one from the sgk_… repository key `get_repository_overview` uses.",
|
|
56
|
+
inputSchema: {
|
|
57
|
+
type: "object",
|
|
58
|
+
properties: {
|
|
59
|
+
repository_id: {
|
|
60
|
+
type: "string",
|
|
61
|
+
description: "The repository whose agent keys to list — its numeric id, as `add_repository` " +
|
|
62
|
+
"returns and `list_repositories` reports, not the `org/repo` handle.",
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
required: ["repository_id"],
|
|
66
|
+
// Closed for the reason every tool here states: `server.ts` forwards
|
|
67
|
+
// `arguments` unvalidated, so an open schema would let a misspelled argument
|
|
68
|
+
// be dropped silently.
|
|
69
|
+
additionalProperties: false,
|
|
70
|
+
},
|
|
71
|
+
async run(args, context) {
|
|
72
|
+
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
73
|
+
const api = requireUserApiConfig(context.config);
|
|
74
|
+
const body = await getJsonObject(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}/agent_keys`, {}, context.fetch);
|
|
75
|
+
// Passed through unreshaped, the standing rule (`types.ts`: "A thin client
|
|
76
|
+
// that reshapes its upstream is not thin") — the rows are the controller's
|
|
77
|
+
// own serialization, and the `id` an agent needs for the revoke is one of
|
|
78
|
+
// the fields a reshape could drop.
|
|
79
|
+
return {
|
|
80
|
+
text: JSON.stringify(body, null, 2),
|
|
81
|
+
structured: body,
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
export default listRepositoryAgentKeys;
|
|
86
|
+
//# sourceMappingURL=list-repository-agent-keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-repository-agent-keys.js","sourceRoot":"","sources":["../../../src/tools/list-repository-agent-keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,uBAAuB,GAAmB;IAC9C,IAAI,EAAE,4BAA4B;IAClC,KAAK,EAAE,4BAA4B;IACnC,WAAW,EACT,4FAA4F;QAC5F,8FAA8F;QAC9F,0EAA0E;QAC1E,+FAA+F;QAC/F,2FAA2F;QAC3F,sBAAsB;QACtB,+FAA+F;QAC/F,wFAAwF;QACxF,8FAA8F;QAC9F,sCAAsC;QACtC,wFAAwF;QACxF,yBAAyB;QACzB,iGAAiG;QACjG,gGAAgG;QAChG,8FAA8F;IAChG,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,gFAAgF;oBAChF,qEAAqE;aACxE;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,CAAC;QAC3B,qEAAqE;QACrE,6EAA6E;QAC7E,uBAAuB;QACvB,oBAAoB,EAAE,KAAK;KAC5B;IAED,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO;QACrB,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC,CAAC;QAE3E,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,MAAM,IAAI,GAAG,MAAM,aAAa,CAC9B,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,aAAa,EACrE,EAAE,EACF,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,2EAA2E;QAC3E,2EAA2E;QAC3E,0EAA0E;QAC1E,mCAAmC;QACnC,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACnC,UAAU,EAAE,IAAI;SACjB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
|
|
@@ -42,10 +42,15 @@ import type { ToolDefinition } from "./types.js";
|
|
|
42
42
|
* ago" is a different fact from "you never had one", and the tool description
|
|
43
43
|
* is where an agent learns to branch on it.
|
|
44
44
|
*
|
|
45
|
-
* == No arguments, for the same reason `list_repositories`
|
|
45
|
+
* == No arguments, for the same reason `list_repositories` used to have none
|
|
46
46
|
*
|
|
47
47
|
* The credential is the whole of the scope. The endpoint takes no parameters,
|
|
48
|
-
* and nothing an argument could select reaches this answer.
|
|
48
|
+
* and nothing an argument could select reaches this answer. (`list_repositories`
|
|
49
|
+
* argued the same way and argued it the same amount — until its endpoint grew
|
|
50
|
+
* the SPGD-940 narrowing asks and the tool grew the arguments that forward
|
|
51
|
+
* them. This endpoint has grown no asks, so the argument-less shape here is
|
|
52
|
+
* still the honest one, and the sentence above keeps saying so rather than
|
|
53
|
+
* inheriting a reason that moved.)
|
|
49
54
|
*/
|
|
50
55
|
declare const registrableRepositories: ToolDefinition;
|
|
51
56
|
export default registrableRepositories;
|
|
@@ -42,10 +42,15 @@ import { getJsonObject, requireUserApiConfig } from "../support/specguard-api.js
|
|
|
42
42
|
* ago" is a different fact from "you never had one", and the tool description
|
|
43
43
|
* is where an agent learns to branch on it.
|
|
44
44
|
*
|
|
45
|
-
* == No arguments, for the same reason `list_repositories`
|
|
45
|
+
* == No arguments, for the same reason `list_repositories` used to have none
|
|
46
46
|
*
|
|
47
47
|
* The credential is the whole of the scope. The endpoint takes no parameters,
|
|
48
|
-
* and nothing an argument could select reaches this answer.
|
|
48
|
+
* and nothing an argument could select reaches this answer. (`list_repositories`
|
|
49
|
+
* argued the same way and argued it the same amount — until its endpoint grew
|
|
50
|
+
* the SPGD-940 narrowing asks and the tool grew the arguments that forward
|
|
51
|
+
* them. This endpoint has grown no asks, so the argument-less shape here is
|
|
52
|
+
* still the honest one, and the sentence above keeps saying so rather than
|
|
53
|
+
* inheriting a reason that moved.)
|
|
49
54
|
*/
|
|
50
55
|
const registrableRepositories = {
|
|
51
56
|
name: "registrable_repositories",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registrable-repositories.js","sourceRoot":"","sources":["../../../src/tools/registrable-repositories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAGlF
|
|
1
|
+
{"version":3,"file":"registrable-repositories.js","sourceRoot":"","sources":["../../../src/tools/registrable-repositories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAGlF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,MAAM,uBAAuB,GAAmB;IAC9C,IAAI,EAAE,0BAA0B;IAChC,KAAK,EAAE,0BAA0B;IACjC,WAAW,EACT,4FAA4F;QAC5F,2FAA2F;QAC3F,sFAAsF;QACtF,6FAA6F;QAC7F,qFAAqF;QACrF,6FAA6F;QAC7F,yFAAyF;QACzF,mFAAmF;QACnF,8FAA8F;QAC9F,yFAAyF;QACzF,8FAA8F;QAC9F,4FAA4F;QAC5F,6FAA6F;QAC7F,wFAAwF;QACxF,4FAA4F;QAC5F,yFAAyF;QACzF,mFAAmF;QACnF,wFAAwF;QACxF,sFAAsF;QACtF,6EAA6E;IAC/E,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,4EAA4E;QAC5E,yEAAyE;QACzE,0EAA0E;QAC1E,0EAA0E;QAC1E,4CAA4C;QAC5C,oBAAoB,EAAE,KAAK;KAC5B;IAED,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO;QACtB,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,MAAM,OAAO,GAAG,MAAM,aAAa,CACjC,GAAG,EACH,kCAAkC,EAClC,EAAE,EACF,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACtC,UAAU,EAAE,OAAO;SACpB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ToolDefinition } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* `DELETE /api/v1/repositories/:repository_id/agent_keys/:id` as a tool —
|
|
4
|
+
* shipped in the platform (`specguard/config/routes.rb`,
|
|
5
|
+
* `Api::V1::UserRepositoryAgentKeysController#destroy`, SPGD-1004, `dfb9892`).
|
|
6
|
+
*
|
|
7
|
+
* == The blast radius is the whole stored set
|
|
8
|
+
*
|
|
9
|
+
* An agent key's grant — a repository set and a permission set — is chosen
|
|
10
|
+
* once at mint time and stored ONCE, so revocation cuts the token on EVERY
|
|
11
|
+
* repository in the set, not only the one this call names. On the web a
|
|
12
|
+
* confirm dialog names that set BEFORE the cut; over the API there is no
|
|
13
|
+
* dialog, so the disclosure travels in the response that performs it: count
|
|
14
|
+
* first, then the still-existing names, with `deleted_repository_count`
|
|
15
|
+
* present only when repositories have been deleted since mint and dropped out
|
|
16
|
+
* of the names. The tool passes the body through rather than answering with a
|
|
17
|
+
* summary of its own — the deployment already wrote the confirmation, and a
|
|
18
|
+
* second wording of it is a second fact free to drift from the first.
|
|
19
|
+
*
|
|
20
|
+
* == 200 WITH a body, not the sibling's 204
|
|
21
|
+
*
|
|
22
|
+
* `revoke_repository_api_key` says "a 204 means revoked" because every
|
|
23
|
+
* endpoint this bridge's DELETEs served until now answered empty. This one
|
|
24
|
+
* deliberately does not: the disclosure body IS the confirmation, so the call
|
|
25
|
+
* routes through `deleteJsonObject` — `requestJson`'s parse — rather than
|
|
26
|
+
* `deleteJson`'s raw-text handling. The difference is carried in the
|
|
27
|
+
* description because a caller pattern-matching on the sibling's contract
|
|
28
|
+
* would otherwise misread the shape of success here.
|
|
29
|
+
*
|
|
30
|
+
* == The id is scoped, and both forks are 404
|
|
31
|
+
*
|
|
32
|
+
* `AgentApiKey.live.find` + `covers?` — a key id that is revoked already (a
|
|
33
|
+
* retained revoked row is not a credential) or whose stored set does not cover
|
|
34
|
+
* THIS repository is a 404, never a cross-repository cut. The bridge relies on
|
|
35
|
+
* that server scoping entirely and adds no client-side check of its own, for
|
|
36
|
+
* the reason every tool here states: the server is the gate.
|
|
37
|
+
*
|
|
38
|
+
* == The id source
|
|
39
|
+
*
|
|
40
|
+
* No mint tool exists (deliberately web-only), so the id comes from
|
|
41
|
+
* `list_repository_agent_keys` alone — stated in the description rather than
|
|
42
|
+
* left implicit.
|
|
43
|
+
*/
|
|
44
|
+
declare const revokeRepositoryAgentKey: ToolDefinition;
|
|
45
|
+
export default revokeRepositoryAgentKey;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { deleteJsonObject, requireUserApiConfig } from "../support/specguard-api.js";
|
|
2
|
+
import { requireString } from "./args.js";
|
|
3
|
+
/**
|
|
4
|
+
* `DELETE /api/v1/repositories/:repository_id/agent_keys/:id` as a tool —
|
|
5
|
+
* shipped in the platform (`specguard/config/routes.rb`,
|
|
6
|
+
* `Api::V1::UserRepositoryAgentKeysController#destroy`, SPGD-1004, `dfb9892`).
|
|
7
|
+
*
|
|
8
|
+
* == The blast radius is the whole stored set
|
|
9
|
+
*
|
|
10
|
+
* An agent key's grant — a repository set and a permission set — is chosen
|
|
11
|
+
* once at mint time and stored ONCE, so revocation cuts the token on EVERY
|
|
12
|
+
* repository in the set, not only the one this call names. On the web a
|
|
13
|
+
* confirm dialog names that set BEFORE the cut; over the API there is no
|
|
14
|
+
* dialog, so the disclosure travels in the response that performs it: count
|
|
15
|
+
* first, then the still-existing names, with `deleted_repository_count`
|
|
16
|
+
* present only when repositories have been deleted since mint and dropped out
|
|
17
|
+
* of the names. The tool passes the body through rather than answering with a
|
|
18
|
+
* summary of its own — the deployment already wrote the confirmation, and a
|
|
19
|
+
* second wording of it is a second fact free to drift from the first.
|
|
20
|
+
*
|
|
21
|
+
* == 200 WITH a body, not the sibling's 204
|
|
22
|
+
*
|
|
23
|
+
* `revoke_repository_api_key` says "a 204 means revoked" because every
|
|
24
|
+
* endpoint this bridge's DELETEs served until now answered empty. This one
|
|
25
|
+
* deliberately does not: the disclosure body IS the confirmation, so the call
|
|
26
|
+
* routes through `deleteJsonObject` — `requestJson`'s parse — rather than
|
|
27
|
+
* `deleteJson`'s raw-text handling. The difference is carried in the
|
|
28
|
+
* description because a caller pattern-matching on the sibling's contract
|
|
29
|
+
* would otherwise misread the shape of success here.
|
|
30
|
+
*
|
|
31
|
+
* == The id is scoped, and both forks are 404
|
|
32
|
+
*
|
|
33
|
+
* `AgentApiKey.live.find` + `covers?` — a key id that is revoked already (a
|
|
34
|
+
* retained revoked row is not a credential) or whose stored set does not cover
|
|
35
|
+
* THIS repository is a 404, never a cross-repository cut. The bridge relies on
|
|
36
|
+
* that server scoping entirely and adds no client-side check of its own, for
|
|
37
|
+
* the reason every tool here states: the server is the gate.
|
|
38
|
+
*
|
|
39
|
+
* == The id source
|
|
40
|
+
*
|
|
41
|
+
* No mint tool exists (deliberately web-only), so the id comes from
|
|
42
|
+
* `list_repository_agent_keys` alone — stated in the description rather than
|
|
43
|
+
* left implicit.
|
|
44
|
+
*/
|
|
45
|
+
const revokeRepositoryAgentKey = {
|
|
46
|
+
name: "revoke_repository_agent_key",
|
|
47
|
+
title: "Revoke repository agent key",
|
|
48
|
+
description: "Revokes one agent key (`sga_…` key) on a SpecGuard repository. IRREVERSIBLE, and the blast " +
|
|
49
|
+
"radius is the key's WHOLE stored set: the grant (repository set + permission set) is stored " +
|
|
50
|
+
"once at mint time, so this one call cuts the token on EVERY repository the key covers, not " +
|
|
51
|
+
"just `repository_id` — check `repository_count` on `list_repository_agent_keys` BEFORE " +
|
|
52
|
+
"cutting a multi-repository key. " +
|
|
53
|
+
"Answers `200` WITH the disclosure body — an `agent_key` block carrying `revoked_at`, " +
|
|
54
|
+
"`repository_count` and the still-existing `repositories` names, plus " +
|
|
55
|
+
"`deleted_repository_count` when some have been deleted since mint — NOT the empty 204 the " +
|
|
56
|
+
"sgk_ sibling `revoke_repository_api_key` serves; the body itself is the confirmation. " +
|
|
57
|
+
"The `key_id` is scoped to `repository_id`: a key whose stored set does not cover this " +
|
|
58
|
+
"repository, or one already revoked, is refused 404, never a cross-repository cut. " +
|
|
59
|
+
"Agent keys have NO mint tool on this bridge (minting is deliberately web-only), so take " +
|
|
60
|
+
"`key_id` from `list_repository_agent_keys` — list first, then revoke. " +
|
|
61
|
+
"Authorization is the `keys_manage` capability — a caller without it is refused 403 in " +
|
|
62
|
+
"SpecGuard's own words. " +
|
|
63
|
+
"Takes `repository_id` (the numeric id `list_repositories` reports) and `key_id`. " +
|
|
64
|
+
"Needs SPECGUARD_USER_API_KEY (an sgu_… key), the same credential the other key-administration " +
|
|
65
|
+
"tools read and a DIFFERENT one from the sgk_… repository key `get_repository_overview` uses.",
|
|
66
|
+
inputSchema: {
|
|
67
|
+
type: "object",
|
|
68
|
+
properties: {
|
|
69
|
+
repository_id: {
|
|
70
|
+
type: "string",
|
|
71
|
+
description: "The repository whose key-administration scope the call is made under — its numeric " +
|
|
72
|
+
"id, as `add_repository` returns and `list_repositories` reports, not the `org/repo` " +
|
|
73
|
+
"handle. The CUT, however, lands on every repository in the key's stored set.",
|
|
74
|
+
},
|
|
75
|
+
key_id: {
|
|
76
|
+
type: "string",
|
|
77
|
+
description: "The id of the agent key to revoke, as served by `list_repository_agent_keys` — " +
|
|
78
|
+
"the only id source, because agent keys have no mint tool on this bridge. Scoped to " +
|
|
79
|
+
"`repository_id`: a key whose stored set excludes this repository, or one already " +
|
|
80
|
+
"revoked, is refused 404.",
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
required: ["repository_id", "key_id"],
|
|
84
|
+
// Closed for the reason every tool here states — and on a DESTRUCTIVE path,
|
|
85
|
+
// a silently dropped misspelled argument must not be able to leave the
|
|
86
|
+
// agent believing it revoked a key the call never named.
|
|
87
|
+
additionalProperties: false,
|
|
88
|
+
},
|
|
89
|
+
async run(args, context) {
|
|
90
|
+
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
91
|
+
const keyId = requireString(args["key_id"], "key_id");
|
|
92
|
+
const api = requireUserApiConfig(context.config);
|
|
93
|
+
// The 200 disclosure body, passed through unreshaped in both halves — the
|
|
94
|
+
// deployment already wrote the confirmation (the stored set, count first),
|
|
95
|
+
// and this is the API's substitute for the web confirm dialog.
|
|
96
|
+
const disclosure = await deleteJsonObject(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}/agent_keys/${encodeURIComponent(keyId)}`, context.fetch);
|
|
97
|
+
return {
|
|
98
|
+
text: JSON.stringify(disclosure, null, 2),
|
|
99
|
+
structured: disclosure,
|
|
100
|
+
};
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
export default revokeRepositoryAgentKey;
|
|
104
|
+
//# sourceMappingURL=revoke-repository-agent-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revoke-repository-agent-key.js","sourceRoot":"","sources":["../../../src/tools/revoke-repository-agent-key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,MAAM,wBAAwB,GAAmB;IAC/C,IAAI,EAAE,6BAA6B;IACnC,KAAK,EAAE,6BAA6B;IACpC,WAAW,EACT,6FAA6F;QAC7F,8FAA8F;QAC9F,6FAA6F;QAC7F,yFAAyF;QACzF,kCAAkC;QAClC,uFAAuF;QACvF,uEAAuE;QACvE,4FAA4F;QAC5F,wFAAwF;QACxF,wFAAwF;QACxF,oFAAoF;QACpF,0FAA0F;QAC1F,wEAAwE;QACxE,wFAAwF;QACxF,yBAAyB;QACzB,mFAAmF;QACnF,gGAAgG;QAChG,8FAA8F;IAChG,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,qFAAqF;oBACrF,sFAAsF;oBACtF,8EAA8E;aACjF;YACD,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,iFAAiF;oBACjF,qFAAqF;oBACrF,mFAAmF;oBACnF,0BAA0B;aAC7B;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,EAAE,QAAQ,CAAC;QACrC,4EAA4E;QAC5E,uEAAuE;QACvE,yDAAyD;QACzD,oBAAoB,EAAE,KAAK;KAC5B;IAED,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO;QACrB,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC,CAAC;QAC3E,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;QAEtD,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,0EAA0E;QAC1E,2EAA2E;QAC3E,+DAA+D;QAC/D,MAAM,UAAU,GAAG,MAAM,gBAAgB,CACvC,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,eAAe,kBAAkB,CAAC,KAAK,CAAC,EAAE,EAClG,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,UAAU,EAAE,UAAU;SACvB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,wBAAwB,CAAC"}
|