specguard-mcp 0.1.3 → 0.1.4
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 +106 -6
- package/dist/src/support/specguard-api.d.ts +17 -0
- package/dist/src/support/specguard-api.js +33 -4
- package/dist/src/support/specguard-api.js.map +1 -1
- package/dist/src/tools/create-repository-api-key.d.ts +26 -0
- package/dist/src/tools/create-repository-api-key.js +83 -0
- package/dist/src/tools/create-repository-api-key.js.map +1 -0
- package/dist/src/tools/index.d.ts +46 -5
- package/dist/src/tools/index.js +54 -5
- package/dist/src/tools/index.js.map +1 -1
- package/dist/src/tools/registrable-repositories.d.ts +51 -0
- package/dist/src/tools/registrable-repositories.js +92 -0
- package/dist/src/tools/registrable-repositories.js.map +1 -0
- package/dist/src/tools/remove-repository.d.ts +33 -0
- package/dist/src/tools/remove-repository.js +81 -0
- package/dist/src/tools/remove-repository.js.map +1 -0
- package/dist/src/tools/revoke-repository-api-key.d.ts +29 -0
- package/dist/src/tools/revoke-repository-api-key.js +85 -0
- package/dist/src/tools/revoke-repository-api-key.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,9 +32,9 @@ refuses to boot and takes the tools that needed no configuration down with it.
|
|
|
32
32
|
|
|
33
33
|
| Variable | Needed by | Default | What it is |
|
|
34
34
|
| --- | --- | --- | --- |
|
|
35
|
-
| `SPECGUARD_ENDPOINT` | `get_repository_overview`, `list_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 |
|
|
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` | — | 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` | — | 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
|
|
|
@@ -351,10 +351,11 @@ decides which table is consulted before any of them is read — so the two are n
|
|
|
351
351
|
setting one does not stand in for the other. Every message this tool produces names the variable
|
|
352
352
|
*it* reads, so a `401` here never sends you to check the key `get_repository_overview` uses.
|
|
353
353
|
|
|
354
|
-
Registering a repository is
|
|
355
|
-
`full_name` this tool reports.
|
|
356
|
-
|
|
357
|
-
for the capability rather than the other way
|
|
354
|
+
Registering a repository is `add_repository`, below — it reads the same `sgu_…` key and takes the
|
|
355
|
+
`full_name` this tool reports. Removal and the key lifecycle (`remove_repository`,
|
|
356
|
+
`create_repository_api_key`, `revoke_repository_api_key`) are below too, on the same key; a tool
|
|
357
|
+
here is a promise the agent will act on, so each waits for the capability rather than the other way
|
|
358
|
+
round.
|
|
358
359
|
|
|
359
360
|
### `add_repository`
|
|
360
361
|
|
|
@@ -398,6 +399,105 @@ as this bridge rejecting a name the platform would have accepted.
|
|
|
398
399
|
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and a
|
|
399
400
|
different one from the `sgk_…` key `get_repository_overview` uses.
|
|
400
401
|
|
|
402
|
+
### `registrable_repositories`
|
|
403
|
+
|
|
404
|
+
Lists the GitHub repositories the person behind `SPECGUARD_USER_API_KEY` **could** register with
|
|
405
|
+
SpecGuard — the set the registration gate would consult, read out loud in advance, so an agent can
|
|
406
|
+
pick a `full_name` for `add_repository` from a real answer rather than by guessing. `list_repositories`
|
|
407
|
+
reports what *is* registered; this reports what could be, and the two answer different questions.
|
|
408
|
+
|
|
409
|
+
The body comes back as SpecGuard serves it: `{"repositories": […]}` with each entry carrying
|
|
410
|
+
`full_name` and `registered`, ordered by `full_name` ascending, plus a `grant` block (`captured_at`,
|
|
411
|
+
`expires_at`, `stale`) describing the stored record of this person's GitHub permissions.
|
|
412
|
+
|
|
413
|
+
**`registered` is asked globally, not just of your own repositories.** An entry marked
|
|
414
|
+
`registered: true` was registered by *somebody* — possibly someone else — and a POST naming it will
|
|
415
|
+
be refused with `has already been taken`. That is exactly why entries are *marked* rather than
|
|
416
|
+
excluded: a reading scoped to what you can open would send you at a name nobody can register.
|
|
417
|
+
|
|
418
|
+
**A name appearing here is not a promise the write will succeed.** This is the set the gate would
|
|
419
|
+
consult at the moment of the read; the repository may be registered by someone else between this
|
|
420
|
+
call and your POST.
|
|
421
|
+
|
|
422
|
+
**A missing or stale grant is not an error — it is the modal first answer.** SpecGuard fails closed
|
|
423
|
+
when it has no current record of your GitHub permissions, which is every person who has not opened
|
|
424
|
+
SpecGuard in a browser recently. The call then answers `403` with SpecGuard's own sentence naming
|
|
425
|
+
the fix: *sign in to SpecGuard in a browser and reconnect GitHub, then try again*. On that refusal
|
|
426
|
+
the body still carries `grant`, and it distinguishes the two cases: `grant: null` means there never
|
|
427
|
+
was one (first-time setup), a populated grant with `stale: true` means an existing connection lapsed
|
|
428
|
+
— same remedy, very different urgency. Read it before telling the person what to do.
|
|
429
|
+
|
|
430
|
+
**This tool takes no arguments** — the credential is the whole of the scope. The endpoint takes no
|
|
431
|
+
parameters; which repositories are in the answer is decided by SpecGuard from the person the key
|
|
432
|
+
speaks for.
|
|
433
|
+
|
|
434
|
+
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
|
|
435
|
+
`add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
|
|
436
|
+
|
|
437
|
+
### `remove_repository`
|
|
438
|
+
|
|
439
|
+
Removes a repository from SpecGuard — and with it **every key, run and intent on it**. This is the
|
|
440
|
+
destructive gesture in this toolset: irreversible, no undo, and a `204` means the repository and its
|
|
441
|
+
history are gone short of re-registering from scratch. Confirm with the user before calling.
|
|
442
|
+
|
|
443
|
+
| argument | |
|
|
444
|
+
| --- | --- |
|
|
445
|
+
| `repository_id` | the repository to remove — its numeric `id`, as `add_repository` returns and `list_repositories` reports, not the `org/repo` handle |
|
|
446
|
+
|
|
447
|
+
Authorization is the `repo.delete` capability at **either surface** — an owner, or a member granted
|
|
448
|
+
`repo.delete`, may remove the repository. A member without it is refused `403` with SpecGuard's own
|
|
449
|
+
sentence, verbatim. The repository's CI keys stop authenticating the moment it succeeds.
|
|
450
|
+
|
|
451
|
+
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
|
|
452
|
+
`add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
|
|
453
|
+
|
|
454
|
+
### `create_repository_api_key`
|
|
455
|
+
|
|
456
|
+
Mints a new CI API key (`sgk_…`) for a SpecGuard repository and returns it alongside the
|
|
457
|
+
repository's existing keys. Minting does not disturb existing keys — each key on a repository
|
|
458
|
+
authenticates independently until revoked.
|
|
459
|
+
|
|
460
|
+
| argument | |
|
|
461
|
+
| --- | --- |
|
|
462
|
+
| `repository_id` | the repository to mint the key for — its numeric `id`, as `add_repository` returns and `list_repositories` reports, not the `org/repo` handle |
|
|
463
|
+
| `name` | an optional label for the key; omit it to let SpecGuard use its default name |
|
|
464
|
+
|
|
465
|
+
The body comes back as SpecGuard serves it: an `api_key` block (`name`, `token`, `hint`,
|
|
466
|
+
`created_at`) — the same shape `add_repository` serves.
|
|
467
|
+
|
|
468
|
+
> ⚠️ **`api_key.token` is shown once and never again.** Nothing stores it and no endpoint can
|
|
469
|
+
> re-serve it. Hand it to the person you are working for in your reply. If it is dropped, the
|
|
470
|
+
> recovery is minting another key with this same tool — the platform has no regenerate — then
|
|
471
|
+
> revoking the orphaned one with `revoke_repository_api_key`.
|
|
472
|
+
|
|
473
|
+
Authorization is the `keys_manage` capability; a member without it is refused `403` with SpecGuard's
|
|
474
|
+
own sentence, verbatim.
|
|
475
|
+
|
|
476
|
+
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
|
|
477
|
+
`add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
|
|
478
|
+
|
|
479
|
+
### `revoke_repository_api_key`
|
|
480
|
+
|
|
481
|
+
Revokes one CI API key on a SpecGuard repository. The key stops authenticating immediately; every
|
|
482
|
+
**other** key on the repository keeps working, so CI keeps ingesting if it holds a surviving key.
|
|
483
|
+
|
|
484
|
+
| argument | |
|
|
485
|
+
| --- | --- |
|
|
486
|
+
| `repository_id` | the repository the key belongs to — its numeric `id`, as `add_repository` returns and `list_repositories` reports, not the `org/repo` handle |
|
|
487
|
+
| `key_id` | the id of the key to revoke, as served in the `api_key` block of `add_repository` or `create_repository_api_key` |
|
|
488
|
+
|
|
489
|
+
The `key_id` is scoped to `repository_id`: a key id belonging to a different repository is refused
|
|
490
|
+
`404`, never a cross-repository delete. Authorization is the `keys_manage` capability; a member
|
|
491
|
+
without it is refused `403` with SpecGuard's own sentence, verbatim.
|
|
492
|
+
|
|
493
|
+
**Key rotation is mint-then-revoke, in that order.** The platform has no regenerate, so mint a
|
|
494
|
+
replacement with `create_repository_api_key` and deploy it BEFORE revoking the old one — revoke
|
|
495
|
+
first and the repository's CI is locked out until a human mints a new key in a browser. A `204`
|
|
496
|
+
means the key is revoked.
|
|
497
|
+
|
|
498
|
+
It reads `SPECGUARD_USER_API_KEY` (`sgu_…`), the same credential as `list_repositories` and
|
|
499
|
+
`add_repository` and a different one from the `sgk_…` key `get_repository_overview` uses.
|
|
500
|
+
|
|
401
501
|
## How it works
|
|
402
502
|
|
|
403
503
|
```
|
|
@@ -25,6 +25,23 @@ export declare function getJson(api: ApiConfig, path: string, query: Record<stri
|
|
|
25
25
|
* send a body whose `Content-Type` says JSON and whose bytes are not.
|
|
26
26
|
*/
|
|
27
27
|
export declare function postJson(api: ApiConfig, path: string, body: Record<string, unknown>, fetchImpl: typeof globalThis.fetch): Promise<unknown>;
|
|
28
|
+
/**
|
|
29
|
+
* `DELETE` — the destructive half of the transport, and deliberately the SAME
|
|
30
|
+
* function underneath `postJson` rather than beside it, for the reason
|
|
31
|
+
* `postJson`'s header states: everything expensive about this module is about
|
|
32
|
+
* the deadline, not the verb.
|
|
33
|
+
*
|
|
34
|
+
* Returns the RAW BODY TEXT rather than a parsed value, because the endpoints
|
|
35
|
+
* this serves answer `204` with NO body at all — the one response in the `sgu_`
|
|
36
|
+
* surface that is deliberately not JSON. `requestJson` JSON-parses every 2xx it
|
|
37
|
+
* sees, so routing a `204` through it would turn a successful delete into
|
|
38
|
+
* "answered 204 but the body was not JSON" — the trap this verb specifically
|
|
39
|
+
* introduces, and the reason the DELETE path has its own success handling
|
|
40
|
+
* instead of sharing `requestJson`'s. The status check and the
|
|
41
|
+
* "reached and refused" hand-off to `describeFailure` are still shared
|
|
42
|
+
* verbatim: only what happens to a SUCCESS body differs.
|
|
43
|
+
*/
|
|
44
|
+
export declare function deleteJson(api: ApiConfig, path: string, fetchImpl: typeof globalThis.fetch): Promise<string>;
|
|
28
45
|
/**
|
|
29
46
|
* `postJson`, narrowed exactly as `getJsonObject` narrows `getJson`.
|
|
30
47
|
*
|
|
@@ -38,6 +38,28 @@ export async function postJson(api, path, body, fetchImpl) {
|
|
|
38
38
|
body: JSON.stringify(body),
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* `DELETE` — the destructive half of the transport, and deliberately the SAME
|
|
43
|
+
* function underneath `postJson` rather than beside it, for the reason
|
|
44
|
+
* `postJson`'s header states: everything expensive about this module is about
|
|
45
|
+
* the deadline, not the verb.
|
|
46
|
+
*
|
|
47
|
+
* Returns the RAW BODY TEXT rather than a parsed value, because the endpoints
|
|
48
|
+
* this serves answer `204` with NO body at all — the one response in the `sgu_`
|
|
49
|
+
* surface that is deliberately not JSON. `requestJson` JSON-parses every 2xx it
|
|
50
|
+
* sees, so routing a `204` through it would turn a successful delete into
|
|
51
|
+
* "answered 204 but the body was not JSON" — the trap this verb specifically
|
|
52
|
+
* introduces, and the reason the DELETE path has its own success handling
|
|
53
|
+
* instead of sharing `requestJson`'s. The status check and the
|
|
54
|
+
* "reached and refused" hand-off to `describeFailure` are still shared
|
|
55
|
+
* verbatim: only what happens to a SUCCESS body differs.
|
|
56
|
+
*/
|
|
57
|
+
export async function deleteJson(api, path, fetchImpl) {
|
|
58
|
+
const { response, body } = await fetchWithTimeout(new URL(`${api.endpoint}${path}`), api, fetchImpl, { method: "DELETE" });
|
|
59
|
+
if (!response.ok)
|
|
60
|
+
throw describeFailure(response.status, body, api);
|
|
61
|
+
return body;
|
|
62
|
+
}
|
|
41
63
|
/**
|
|
42
64
|
* `postJson`, narrowed exactly as `getJsonObject` narrows `getJson`.
|
|
43
65
|
*
|
|
@@ -245,8 +267,8 @@ function describeFailure(status, body, api) {
|
|
|
245
267
|
return new ApiError(`${api.endpoint} has no such endpoint (404). Check that ${api.endpointVariable} is the ` +
|
|
246
268
|
"deployment's root URL, without a path.", status);
|
|
247
269
|
}
|
|
248
|
-
if (status === 400) {
|
|
249
|
-
const message =
|
|
270
|
+
if (status === 400 || status === 403) {
|
|
271
|
+
const message = refusalMessage(body, status);
|
|
250
272
|
if (message !== undefined)
|
|
251
273
|
return new ApiError(message, status);
|
|
252
274
|
}
|
|
@@ -262,6 +284,13 @@ function describeFailure(status, body, api) {
|
|
|
262
284
|
* `origin/main` route here, so this branch serves the API surface rather than
|
|
263
285
|
* one tool.
|
|
264
286
|
*
|
|
287
|
+
* The 403 is the same shape under another status. `UserRepositoriesController#
|
|
288
|
+
* render_not_granted` renders `{error: "not_granted", message:, grant:}` — the
|
|
289
|
+
* `grant` block is simply ignored by the extractor, exactly as `details` is.
|
|
290
|
+
* Same defect (the generic branch truncating the one sentence that names the
|
|
291
|
+
* fix), same remedy — which is why the helper is ONE function parameterised on
|
|
292
|
+
* the status rather than two copies beside each other.
|
|
293
|
+
*
|
|
265
294
|
* SURFACING IT IS THE OPPOSITE OF RESHAPING IT. The generic branch below turns
|
|
266
295
|
* the most useful sentence in this direction —
|
|
267
296
|
*
|
|
@@ -283,7 +312,7 @@ function describeFailure(status, body, api) {
|
|
|
283
312
|
* whose `message` is absent or is not a string — still gets the generic
|
|
284
313
|
* sentence, which at least shows the operator what actually came back.
|
|
285
314
|
*/
|
|
286
|
-
function
|
|
315
|
+
function refusalMessage(body, status) {
|
|
287
316
|
let parsed;
|
|
288
317
|
try {
|
|
289
318
|
parsed = JSON.parse(body);
|
|
@@ -296,7 +325,7 @@ function badRequestMessage(body) {
|
|
|
296
325
|
const message = parsed["message"];
|
|
297
326
|
if (typeof message !== "string" || message.trim() === "")
|
|
298
327
|
return undefined;
|
|
299
|
-
return `SpecGuard refused the request (
|
|
328
|
+
return `SpecGuard refused the request (${status}): ${message.trim()}`;
|
|
300
329
|
}
|
|
301
330
|
export { requireApiConfig, requireUserApiConfig };
|
|
302
331
|
//# sourceMappingURL=specguard-api.js.map
|
|
@@ -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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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ToolDefinition } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* `POST /api/v1/repositories/:repository_id/api_keys` as a tool — shipped in
|
|
4
|
+
* the platform (`specguard/config/routes.rb:158`,
|
|
5
|
+
* `user_repository_api_keys_controller#create`, SPGD-754).
|
|
6
|
+
*
|
|
7
|
+
* == Reveal-once, again
|
|
8
|
+
*
|
|
9
|
+
* The 201 body carries `api_key.token` — the raw key, the only time it exists
|
|
10
|
+
* anywhere — exactly as `add_repository`'s does. The body is therefore passed
|
|
11
|
+
* through UNRESHAPED in both `text` and `structured` for the same reason that
|
|
12
|
+
* tool states: any reshaping on this hop is a value that cannot be recovered
|
|
13
|
+
* rather than a field that can be re-fetched. Recovery for a dropped token is
|
|
14
|
+
* minting another key — this same tool — because the platform ships no
|
|
15
|
+
* `#regenerate` and no re-serve.
|
|
16
|
+
*
|
|
17
|
+
* == The name is top-level and optional
|
|
18
|
+
*
|
|
19
|
+
* `params[:name]` defaults to `ApiKey::DEFAULT_NAME` server-side; `undefined`
|
|
20
|
+
* here means "let the server name it" and simply omits the key from the POST
|
|
21
|
+
* body. Not re-validated here for the reason `add_repository` states: a second
|
|
22
|
+
* format rule on this side is a rule with no owner, free to drift from the one
|
|
23
|
+
* that actually decides.
|
|
24
|
+
*/
|
|
25
|
+
declare const createRepositoryApiKey: ToolDefinition;
|
|
26
|
+
export default createRepositoryApiKey;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { postJsonObject, requireUserApiConfig } from "../support/specguard-api.js";
|
|
2
|
+
import { optionalString, requireString } from "./args.js";
|
|
3
|
+
/**
|
|
4
|
+
* `POST /api/v1/repositories/:repository_id/api_keys` as a tool — shipped in
|
|
5
|
+
* the platform (`specguard/config/routes.rb:158`,
|
|
6
|
+
* `user_repository_api_keys_controller#create`, SPGD-754).
|
|
7
|
+
*
|
|
8
|
+
* == Reveal-once, again
|
|
9
|
+
*
|
|
10
|
+
* The 201 body carries `api_key.token` — the raw key, the only time it exists
|
|
11
|
+
* anywhere — exactly as `add_repository`'s does. The body is therefore passed
|
|
12
|
+
* through UNRESHAPED in both `text` and `structured` for the same reason that
|
|
13
|
+
* tool states: any reshaping on this hop is a value that cannot be recovered
|
|
14
|
+
* rather than a field that can be re-fetched. Recovery for a dropped token is
|
|
15
|
+
* minting another key — this same tool — because the platform ships no
|
|
16
|
+
* `#regenerate` and no re-serve.
|
|
17
|
+
*
|
|
18
|
+
* == The name is top-level and optional
|
|
19
|
+
*
|
|
20
|
+
* `params[:name]` defaults to `ApiKey::DEFAULT_NAME` server-side; `undefined`
|
|
21
|
+
* here means "let the server name it" and simply omits the key from the POST
|
|
22
|
+
* body. Not re-validated here for the reason `add_repository` states: a second
|
|
23
|
+
* format rule on this side is a rule with no owner, free to drift from the one
|
|
24
|
+
* that actually decides.
|
|
25
|
+
*/
|
|
26
|
+
const createRepositoryApiKey = {
|
|
27
|
+
name: "create_repository_api_key",
|
|
28
|
+
title: "Create repository API key",
|
|
29
|
+
description: "Mints a new CI API key (an sgk_… key) for a SpecGuard repository, and returns it " +
|
|
30
|
+
"alongside the repository's existing keys. " +
|
|
31
|
+
"⚠️ `api_key.token` is shown THIS ONCE AND NEVER AGAIN — nothing stores it and no " +
|
|
32
|
+
"endpoint can re-serve it, so hand it to the user in your reply rather than assuming " +
|
|
33
|
+
"it can be fetched later. If it is dropped, the recovery is minting another key with " +
|
|
34
|
+
"this same tool (the platform has no regenerate), then revoking the orphaned one. " +
|
|
35
|
+
"On success the response carries an `api_key` block (`name`, `token`, `hint`, " +
|
|
36
|
+
"`created_at`) — the same reveal-once shape `add_repository` serves. " +
|
|
37
|
+
"Minting does not disturb existing keys: each key on a repository authenticates " +
|
|
38
|
+
"independently until revoked. " +
|
|
39
|
+
"Takes `repository_id` (the numeric id `list_repositories` reports) and an optional " +
|
|
40
|
+
"`name`, which the server defaults when omitted. " +
|
|
41
|
+
"Authorization is the `keys_manage` capability — a member without it is refused 403 " +
|
|
42
|
+
"in SpecGuard's own words. " +
|
|
43
|
+
"Needs SPECGUARD_USER_API_KEY (an sgu_… key), the same credential `add_repository` " +
|
|
44
|
+
"writes with and a DIFFERENT one from the sgk_… repository key " +
|
|
45
|
+
"`get_repository_overview` uses.",
|
|
46
|
+
inputSchema: {
|
|
47
|
+
type: "object",
|
|
48
|
+
properties: {
|
|
49
|
+
repository_id: {
|
|
50
|
+
type: "string",
|
|
51
|
+
description: "The repository to mint the key for — its numeric id, as `add_repository` " +
|
|
52
|
+
"returns and `list_repositories` reports, not the `org/repo` handle.",
|
|
53
|
+
},
|
|
54
|
+
name: {
|
|
55
|
+
type: "string",
|
|
56
|
+
description: "An optional label for the key. Omit it to let SpecGuard use its default name. " +
|
|
57
|
+
"The server validates the name and refuses an unusable one in its own words.",
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
required: ["repository_id"],
|
|
61
|
+
// Closed for the reason every tool here states — and on a WRITE, a silently
|
|
62
|
+
// dropped misspelled argument still mints something, just possibly mislabeled.
|
|
63
|
+
additionalProperties: false,
|
|
64
|
+
},
|
|
65
|
+
async run(args, context) {
|
|
66
|
+
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
67
|
+
const name = optionalString(args["name"], "name");
|
|
68
|
+
const api = requireUserApiConfig(context.config);
|
|
69
|
+
// `name` omitted when absent rather than sent as null, so the server's own
|
|
70
|
+
// `ApiKey::DEFAULT_NAME` default applies — this bridge expresses "no
|
|
71
|
+
// preference", it does not choose on the server's behalf.
|
|
72
|
+
const created = await postJsonObject(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}/api_keys`, name === undefined ? {} : { name }, context.fetch);
|
|
73
|
+
// Unreshaped, for the reason `add_repository` states at its own return:
|
|
74
|
+
// `api_key.token` exists nowhere else, so any reshaping on this hop is a
|
|
75
|
+
// value that cannot be recovered.
|
|
76
|
+
return {
|
|
77
|
+
text: JSON.stringify(created, null, 2),
|
|
78
|
+
structured: created,
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
export default createRepositoryApiKey;
|
|
83
|
+
//# sourceMappingURL=create-repository-api-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-repository-api-key.js","sourceRoot":"","sources":["../../../src/tools/create-repository-api-key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,sBAAsB,GAAmB;IAC7C,IAAI,EAAE,2BAA2B;IACjC,KAAK,EAAE,2BAA2B;IAClC,WAAW,EACT,mFAAmF;QACnF,4CAA4C;QAC5C,mFAAmF;QACnF,sFAAsF;QACtF,sFAAsF;QACtF,mFAAmF;QACnF,+EAA+E;QAC/E,sEAAsE;QACtE,iFAAiF;QACjF,+BAA+B;QAC/B,qFAAqF;QACrF,kDAAkD;QAClD,qFAAqF;QACrF,4BAA4B;QAC5B,oFAAoF;QACpF,gEAAgE;QAChE,iCAAiC;IACnC,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,2EAA2E;oBAC3E,qEAAqE;aACxE;YACD,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,gFAAgF;oBAChF,6EAA6E;aAChF;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,CAAC;QAC3B,4EAA4E;QAC5E,+EAA+E;QAC/E,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,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;QAElD,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEjD,2EAA2E;QAC3E,qEAAqE;QACrE,0DAA0D;QAC1D,MAAM,OAAO,GAAG,MAAM,cAAc,CAClC,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,WAAW,EACnE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAClC,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,wEAAwE;QACxE,yEAAyE;QACzE,kCAAkC;QAClC,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,sBAAsB,CAAC"}
|
|
@@ -56,11 +56,52 @@ import type { ToolDefinition } from "./types.js";
|
|
|
56
56
|
* beside it, and `describeFailure` grew the `400` branch that surfaces
|
|
57
57
|
* SpecGuard's own refusal sentence — the modal answer this endpoint gives.
|
|
58
58
|
*
|
|
59
|
-
* The standing rule is unchanged and still binding
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* platform, not the bar.
|
|
59
|
+
* The standing rule is unchanged and still binding. What once kept `DELETE
|
|
60
|
+
* /api/v1/repositories/:id` and the API-key endpoints out under it — "not on
|
|
61
|
+
* `origin/main`, so they may not be wrapped" — stopped being true when SPGD-754
|
|
62
|
+
* shipped them, and the sixth-through-eighth section below records their
|
|
63
|
+
* wrapping. What moved was the platform, not the bar.
|
|
64
|
+
*
|
|
65
|
+
* == The fifth: the read half of the registration gate
|
|
66
|
+
*
|
|
67
|
+
* - `registrable_repositories` wraps `GET /api/v1/repositories/registrable`
|
|
68
|
+
* (shipped: `specguard/config/routes.rb:117`,
|
|
69
|
+
* `Api::V1::UserRepositoriesController#registrable`).
|
|
70
|
+
*
|
|
71
|
+
* `list_repositories` says what IS registered; this says what COULD be — the
|
|
72
|
+
* set the gate would consult, read out in advance, so an agent can pick a
|
|
73
|
+
* `full_name` for `add_repository` from a real answer. Landing it also
|
|
74
|
+
* generalised the 400 branch in `describeFailure` into a status-parameterised
|
|
75
|
+
* extractor, because this endpoint's modal first answer is a 403 (`not_granted`)
|
|
76
|
+
* carrying the same `{error, message}` contract — the identical defect, given
|
|
77
|
+
* the identical remedy.
|
|
78
|
+
*
|
|
79
|
+
* The user-scoped surface as it now stands is therefore three tools: read the
|
|
80
|
+
* list, read the gate's answer, write a registration. The standing rule is
|
|
81
|
+
* unchanged and still binding, which is what keeps the rest out:
|
|
82
|
+
* `DELETE /api/v1/repositories/:id` and the API-key endpoints (SPGD-754) are
|
|
83
|
+
* NOT on `origin/main`, so they may not be wrapped here however useful a tool
|
|
84
|
+
* for them would be. What moved was the platform, not the bar.
|
|
85
|
+
*
|
|
86
|
+
* == The sixth through eighth: removal and the key lifecycle
|
|
87
|
+
*
|
|
88
|
+
* - `remove_repository` wraps `DELETE /api/v1/repositories/:id`, and
|
|
89
|
+
* `create_repository_api_key` / `revoke_repository_api_key` wrap the two
|
|
90
|
+
* `api_keys` endpoints (all shipped: SPGD-754, `specguard@origin/main`).
|
|
91
|
+
*
|
|
92
|
+
* The closing fence the two paragraphs above share — "the DELETE and API-key
|
|
93
|
+
* endpoints are NOT on `origin/main`, so they may not be wrapped" — stopped
|
|
94
|
+
* being true when SPGD-754 landed, and these three entries are what became
|
|
95
|
+
* wrappable the moment it did. They also forced the transport's third verb:
|
|
96
|
+
* both DELETE endpoints answer `204` with NO body, the one response in the
|
|
97
|
+
* `sgu_` surface that is deliberately not JSON, which is why `deleteJson`
|
|
98
|
+
* returns the raw body text instead of routing an empty 204 through
|
|
99
|
+
* `requestJson`'s JSON parse.
|
|
100
|
+
*
|
|
101
|
+
* The standing rule itself is unchanged and still binding — which still keeps
|
|
102
|
+
* out `/check-intent`, duplicate clustering, member management and rename: none
|
|
103
|
+
* of their backing endpoints has shipped, and a tool advertised in `tools/list`
|
|
104
|
+
* remains a promise an agent will act on.
|
|
64
105
|
*/
|
|
65
106
|
export declare const TOOLS: readonly ToolDefinition[];
|
|
66
107
|
export type { ToolContext, ToolDefinition, ToolResult } from "./types.js";
|
package/dist/src/tools/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import addRepository from "./add-repository.js";
|
|
2
|
+
import createRepositoryApiKey from "./create-repository-api-key.js";
|
|
2
3
|
import lintIntentAnnotations from "./lint-intent-annotations.js";
|
|
3
4
|
import listRepositories from "./list-repositories.js";
|
|
4
5
|
import getRepositoryOverview from "./repository-overview.js";
|
|
6
|
+
import registrableRepositories from "./registrable-repositories.js";
|
|
7
|
+
import removeRepository from "./remove-repository.js";
|
|
8
|
+
import revokeRepositoryApiKey from "./revoke-repository-api-key.js";
|
|
5
9
|
/**
|
|
6
10
|
* THE REGISTRY — the one file that changes when the toolset grows.
|
|
7
11
|
*
|
|
@@ -59,16 +63,61 @@ import getRepositoryOverview from "./repository-overview.js";
|
|
|
59
63
|
* beside it, and `describeFailure` grew the `400` branch that surfaces
|
|
60
64
|
* SpecGuard's own refusal sentence — the modal answer this endpoint gives.
|
|
61
65
|
*
|
|
62
|
-
* The standing rule is unchanged and still binding
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* platform, not the bar.
|
|
66
|
+
* The standing rule is unchanged and still binding. What once kept `DELETE
|
|
67
|
+
* /api/v1/repositories/:id` and the API-key endpoints out under it — "not on
|
|
68
|
+
* `origin/main`, so they may not be wrapped" — stopped being true when SPGD-754
|
|
69
|
+
* shipped them, and the sixth-through-eighth section below records their
|
|
70
|
+
* wrapping. What moved was the platform, not the bar.
|
|
71
|
+
*
|
|
72
|
+
* == The fifth: the read half of the registration gate
|
|
73
|
+
*
|
|
74
|
+
* - `registrable_repositories` wraps `GET /api/v1/repositories/registrable`
|
|
75
|
+
* (shipped: `specguard/config/routes.rb:117`,
|
|
76
|
+
* `Api::V1::UserRepositoriesController#registrable`).
|
|
77
|
+
*
|
|
78
|
+
* `list_repositories` says what IS registered; this says what COULD be — the
|
|
79
|
+
* set the gate would consult, read out in advance, so an agent can pick a
|
|
80
|
+
* `full_name` for `add_repository` from a real answer. Landing it also
|
|
81
|
+
* generalised the 400 branch in `describeFailure` into a status-parameterised
|
|
82
|
+
* extractor, because this endpoint's modal first answer is a 403 (`not_granted`)
|
|
83
|
+
* carrying the same `{error, message}` contract — the identical defect, given
|
|
84
|
+
* the identical remedy.
|
|
85
|
+
*
|
|
86
|
+
* The user-scoped surface as it now stands is therefore three tools: read the
|
|
87
|
+
* list, read the gate's answer, write a registration. The standing rule is
|
|
88
|
+
* unchanged and still binding, which is what keeps the rest out:
|
|
89
|
+
* `DELETE /api/v1/repositories/:id` and the API-key endpoints (SPGD-754) are
|
|
90
|
+
* NOT on `origin/main`, so they may not be wrapped here however useful a tool
|
|
91
|
+
* for them would be. What moved was the platform, not the bar.
|
|
92
|
+
*
|
|
93
|
+
* == The sixth through eighth: removal and the key lifecycle
|
|
94
|
+
*
|
|
95
|
+
* - `remove_repository` wraps `DELETE /api/v1/repositories/:id`, and
|
|
96
|
+
* `create_repository_api_key` / `revoke_repository_api_key` wrap the two
|
|
97
|
+
* `api_keys` endpoints (all shipped: SPGD-754, `specguard@origin/main`).
|
|
98
|
+
*
|
|
99
|
+
* The closing fence the two paragraphs above share — "the DELETE and API-key
|
|
100
|
+
* endpoints are NOT on `origin/main`, so they may not be wrapped" — stopped
|
|
101
|
+
* being true when SPGD-754 landed, and these three entries are what became
|
|
102
|
+
* wrappable the moment it did. They also forced the transport's third verb:
|
|
103
|
+
* both DELETE endpoints answer `204` with NO body, the one response in the
|
|
104
|
+
* `sgu_` surface that is deliberately not JSON, which is why `deleteJson`
|
|
105
|
+
* returns the raw body text instead of routing an empty 204 through
|
|
106
|
+
* `requestJson`'s JSON parse.
|
|
107
|
+
*
|
|
108
|
+
* The standing rule itself is unchanged and still binding — which still keeps
|
|
109
|
+
* out `/check-intent`, duplicate clustering, member management and rename: none
|
|
110
|
+
* of their backing endpoints has shipped, and a tool advertised in `tools/list`
|
|
111
|
+
* remains a promise an agent will act on.
|
|
67
112
|
*/
|
|
68
113
|
export const TOOLS = [
|
|
69
114
|
lintIntentAnnotations,
|
|
70
115
|
getRepositoryOverview,
|
|
71
116
|
listRepositories,
|
|
72
117
|
addRepository,
|
|
118
|
+
registrableRepositories,
|
|
119
|
+
removeRepository,
|
|
120
|
+
createRepositoryApiKey,
|
|
121
|
+
revokeRepositoryApiKey,
|
|
73
122
|
];
|
|
74
123
|
//# 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,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,qBAAqB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,qBAAqB,MAAM,0BAA0B,CAAC;AAC7D,OAAO,uBAAuB,MAAM,+BAA+B,CAAC;AACpE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AAGpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuGG;AACH,MAAM,CAAC,MAAM,KAAK,GAA8B;IAC9C,qBAAqB;IACrB,qBAAqB;IACrB,gBAAgB;IAChB,aAAa;IACb,uBAAuB;IACvB,gBAAgB;IAChB,sBAAsB;IACtB,sBAAsB;CACvB,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ToolDefinition } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* `GET /api/v1/repositories/registrable` as a tool — shipped today in the
|
|
4
|
+
* platform (`specguard/config/routes.rb:117`, served by
|
|
5
|
+
* `Api::V1::UserRepositoriesController#registrable`).
|
|
6
|
+
*
|
|
7
|
+
* == What it answers, and why `list_repositories` does not
|
|
8
|
+
*
|
|
9
|
+
* `list_repositories` reports what is already registered; this reports what
|
|
10
|
+
* COULD be — the repositories the registration gate would consult, read out
|
|
11
|
+
* loud in advance. It exists so an agent can pick a `full_name` for
|
|
12
|
+
* `add_repository` from a real answer rather than by guessing, and so a
|
|
13
|
+
* `has already been taken` refusal can be explained rather than merely
|
|
14
|
+
* retried.
|
|
15
|
+
*
|
|
16
|
+
* == Two controller decisions the description carries, because both are
|
|
17
|
+
* counter-intuitive and both are stated in the controller's own comments
|
|
18
|
+
*
|
|
19
|
+
* `registered` is asked of `Repository` GLOBALLY, not of what this person can
|
|
20
|
+
* open. The controller says why: a repository somebody ELSE registered still
|
|
21
|
+
* refuses this person's POST with `has already been taken`, so a reading
|
|
22
|
+
* scoped to what they can see would mark it `registered: false` and send them
|
|
23
|
+
* at a name that cannot be registered by anyone. An entry is therefore
|
|
24
|
+
* MARKED, not excluded — `registered: true` is the answer to "why did my POST
|
|
25
|
+
* say has already been taken".
|
|
26
|
+
*
|
|
27
|
+
* And a name appearing here is NOT a promise the write will succeed. This is
|
|
28
|
+
* the set the gate would consult at the moment of the read; the repository may
|
|
29
|
+
* be registered by someone else between the two calls.
|
|
30
|
+
*
|
|
31
|
+
* == The modal first answer is a 403, and that is why `describeFailure` grew
|
|
32
|
+
*
|
|
33
|
+
* `#registrable` fails closed on the two states `GrantVerifier` refuses on and
|
|
34
|
+
* renders `status: :forbidden` — NOT the 400 path the other refusals use. A
|
|
35
|
+
* nil grant is, in the controller's own words, "an ordinary state and not an
|
|
36
|
+
* error: it is every person who has not opened SpecGuard in a browser since
|
|
37
|
+
* this shipped" — so the 403 is the modal first answer this tool gives, and
|
|
38
|
+
* the sentence it carries (sign in, reconnect GitHub, retry) reaches the agent
|
|
39
|
+
* through the 403 branch in `specguard-api.ts`, which this tool is the reason
|
|
40
|
+
* for. On refusal the body still carries `grant`: `null` when there never was
|
|
41
|
+
* one, populated with `stale: true` when it lapsed — "yours lapsed four days
|
|
42
|
+
* ago" is a different fact from "you never had one", and the tool description
|
|
43
|
+
* is where an agent learns to branch on it.
|
|
44
|
+
*
|
|
45
|
+
* == No arguments, for the same reason `list_repositories` has none
|
|
46
|
+
*
|
|
47
|
+
* The credential is the whole of the scope. The endpoint takes no parameters,
|
|
48
|
+
* and nothing an argument could select reaches this answer.
|
|
49
|
+
*/
|
|
50
|
+
declare const registrableRepositories: ToolDefinition;
|
|
51
|
+
export default registrableRepositories;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { getJsonObject, requireUserApiConfig } from "../support/specguard-api.js";
|
|
2
|
+
/**
|
|
3
|
+
* `GET /api/v1/repositories/registrable` as a tool — shipped today in the
|
|
4
|
+
* platform (`specguard/config/routes.rb:117`, served by
|
|
5
|
+
* `Api::V1::UserRepositoriesController#registrable`).
|
|
6
|
+
*
|
|
7
|
+
* == What it answers, and why `list_repositories` does not
|
|
8
|
+
*
|
|
9
|
+
* `list_repositories` reports what is already registered; this reports what
|
|
10
|
+
* COULD be — the repositories the registration gate would consult, read out
|
|
11
|
+
* loud in advance. It exists so an agent can pick a `full_name` for
|
|
12
|
+
* `add_repository` from a real answer rather than by guessing, and so a
|
|
13
|
+
* `has already been taken` refusal can be explained rather than merely
|
|
14
|
+
* retried.
|
|
15
|
+
*
|
|
16
|
+
* == Two controller decisions the description carries, because both are
|
|
17
|
+
* counter-intuitive and both are stated in the controller's own comments
|
|
18
|
+
*
|
|
19
|
+
* `registered` is asked of `Repository` GLOBALLY, not of what this person can
|
|
20
|
+
* open. The controller says why: a repository somebody ELSE registered still
|
|
21
|
+
* refuses this person's POST with `has already been taken`, so a reading
|
|
22
|
+
* scoped to what they can see would mark it `registered: false` and send them
|
|
23
|
+
* at a name that cannot be registered by anyone. An entry is therefore
|
|
24
|
+
* MARKED, not excluded — `registered: true` is the answer to "why did my POST
|
|
25
|
+
* say has already been taken".
|
|
26
|
+
*
|
|
27
|
+
* And a name appearing here is NOT a promise the write will succeed. This is
|
|
28
|
+
* the set the gate would consult at the moment of the read; the repository may
|
|
29
|
+
* be registered by someone else between the two calls.
|
|
30
|
+
*
|
|
31
|
+
* == The modal first answer is a 403, and that is why `describeFailure` grew
|
|
32
|
+
*
|
|
33
|
+
* `#registrable` fails closed on the two states `GrantVerifier` refuses on and
|
|
34
|
+
* renders `status: :forbidden` — NOT the 400 path the other refusals use. A
|
|
35
|
+
* nil grant is, in the controller's own words, "an ordinary state and not an
|
|
36
|
+
* error: it is every person who has not opened SpecGuard in a browser since
|
|
37
|
+
* this shipped" — so the 403 is the modal first answer this tool gives, and
|
|
38
|
+
* the sentence it carries (sign in, reconnect GitHub, retry) reaches the agent
|
|
39
|
+
* through the 403 branch in `specguard-api.ts`, which this tool is the reason
|
|
40
|
+
* for. On refusal the body still carries `grant`: `null` when there never was
|
|
41
|
+
* one, populated with `stale: true` when it lapsed — "yours lapsed four days
|
|
42
|
+
* ago" is a different fact from "you never had one", and the tool description
|
|
43
|
+
* is where an agent learns to branch on it.
|
|
44
|
+
*
|
|
45
|
+
* == No arguments, for the same reason `list_repositories` has none
|
|
46
|
+
*
|
|
47
|
+
* The credential is the whole of the scope. The endpoint takes no parameters,
|
|
48
|
+
* and nothing an argument could select reaches this answer.
|
|
49
|
+
*/
|
|
50
|
+
const registrableRepositories = {
|
|
51
|
+
name: "registrable_repositories",
|
|
52
|
+
title: "Registrable repositories",
|
|
53
|
+
description: "Lists the GitHub repositories the person behind this server's user API key could register " +
|
|
54
|
+
"with SpecGuard — the set the registration gate would consult, read out in advance, so an " +
|
|
55
|
+
"agent can pick a `full_name` for `add_repository` from a real answer rather than by " +
|
|
56
|
+
"guessing. Each entry carries `full_name` and `registered`. `registered` is asked GLOBALLY, " +
|
|
57
|
+
"not just of this person's own repositories: an entry marked `registered: true` was " +
|
|
58
|
+
"registered by SOMEBODY — possibly someone else — and a POST naming it will be refused with " +
|
|
59
|
+
"`has already been taken`, which is exactly the question this flag answers. Entries are " +
|
|
60
|
+
"marked, not excluded, for that reason. The response also carries a `grant` block " +
|
|
61
|
+
"(`captured_at`, `expires_at`, `stale`) describing the stored record of this person's GitHub " +
|
|
62
|
+
"permissions. A MISSING or STALE grant is not an error — it is every person who has not " +
|
|
63
|
+
"opened SpecGuard in a browser recently — and the call then answers 403 with SpecGuard's own " +
|
|
64
|
+
"sentence naming the fix: sign in to SpecGuard in a browser and reconnect GitHub, then try " +
|
|
65
|
+
"again. On that refusal the body's `grant` distinguishes the two cases: `grant: null` means " +
|
|
66
|
+
"there never was one (first-time setup), a populated grant with `stale: true` means an " +
|
|
67
|
+
"existing connection lapsed (same remedy, likely faster to complete) — branch on it before " +
|
|
68
|
+
"telling the person what to do. A name appearing in the list is not a promise the write " +
|
|
69
|
+
"will succeed: someone may register it between this read and the POST. Ordered by " +
|
|
70
|
+
"`full_name` ascending, which is stable across calls. Needs SPECGUARD_USER_API_KEY (an " +
|
|
71
|
+
"sgu_… key), the same credential `list_repositories` and `add_repository` read and a " +
|
|
72
|
+
"DIFFERENT one from the sgk_… repository key `get_repository_overview` uses.",
|
|
73
|
+
inputSchema: {
|
|
74
|
+
type: "object",
|
|
75
|
+
// No properties, deliberately — see this file's header. Still CLOSED rather
|
|
76
|
+
// than merely empty, for the reason `list-repositories.ts` gives inline:
|
|
77
|
+
// `server.ts` forwards `arguments` unvalidated and `run` ignores them, so
|
|
78
|
+
// an open schema would have an invented argument silently dropped and the
|
|
79
|
+
// call answered as if it had been honoured.
|
|
80
|
+
additionalProperties: false,
|
|
81
|
+
},
|
|
82
|
+
async run(_args, context) {
|
|
83
|
+
const api = requireUserApiConfig(context.config);
|
|
84
|
+
const listing = await getJsonObject(api, "/api/v1/repositories/registrable", {}, context.fetch);
|
|
85
|
+
return {
|
|
86
|
+
text: JSON.stringify(listing, null, 2),
|
|
87
|
+
structured: listing,
|
|
88
|
+
};
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
export default registrableRepositories;
|
|
92
|
+
//# sourceMappingURL=registrable-repositories.js.map
|
|
@@ -0,0 +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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;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,33 @@
|
|
|
1
|
+
import type { ToolDefinition } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* `DELETE /api/v1/repositories/:id` as a tool — shipped in the platform
|
|
4
|
+
* (`specguard/config/routes.rb:152`, `Api::V1::UserRepositoriesController#destroy`,
|
|
5
|
+
* SPGD-754).
|
|
6
|
+
*
|
|
7
|
+
* == The destructive gesture in the whole surface
|
|
8
|
+
*
|
|
9
|
+
* Everything else here reads, registers, or mints. This one removes a
|
|
10
|
+
* repository AND every key, run and intent on it (`memberships_helper.rb`:
|
|
11
|
+
* "Delete the repository, and every key, run and intent on it"), and there is no
|
|
12
|
+
* undo. The description therefore carries the hazard BEFORE the call: it is
|
|
13
|
+
* prompt material, read when the agent is deciding whether to act, not a
|
|
14
|
+
* footnote discovered after.
|
|
15
|
+
*
|
|
16
|
+
* == Authorization is `repo.delete` at either surface
|
|
17
|
+
*
|
|
18
|
+
* The controller authorizes through `RepositoryAuthorization`'s `:repo_delete`
|
|
19
|
+
* fork — deliberately NOT `:owner` — so a member granted `repo.delete` may
|
|
20
|
+
* remove the repository from either surface. The tool does not probe for the
|
|
21
|
+
* capability client-side: the server is the gate, and a member without it
|
|
22
|
+
* receives a 403 whose sentence arrives verbatim through the landed
|
|
23
|
+
* `refusalMessage` branch in `describeFailure`.
|
|
24
|
+
*
|
|
25
|
+
* == 204 with no body
|
|
26
|
+
*
|
|
27
|
+
* This is the one response in the `sgu_` surface that is deliberately not a
|
|
28
|
+
* JSON body — which is why `deleteJson` exists: routing an empty-body 204
|
|
29
|
+
* through `requestJson`'s JSON parse would turn a successful delete into
|
|
30
|
+
* "the body was not JSON". Here, no body IS the success.
|
|
31
|
+
*/
|
|
32
|
+
declare const removeRepository: ToolDefinition;
|
|
33
|
+
export default removeRepository;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { deleteJson, requireUserApiConfig } from "../support/specguard-api.js";
|
|
2
|
+
import { requireString } from "./args.js";
|
|
3
|
+
/**
|
|
4
|
+
* `DELETE /api/v1/repositories/:id` as a tool — shipped in the platform
|
|
5
|
+
* (`specguard/config/routes.rb:152`, `Api::V1::UserRepositoriesController#destroy`,
|
|
6
|
+
* SPGD-754).
|
|
7
|
+
*
|
|
8
|
+
* == The destructive gesture in the whole surface
|
|
9
|
+
*
|
|
10
|
+
* Everything else here reads, registers, or mints. This one removes a
|
|
11
|
+
* repository AND every key, run and intent on it (`memberships_helper.rb`:
|
|
12
|
+
* "Delete the repository, and every key, run and intent on it"), and there is no
|
|
13
|
+
* undo. The description therefore carries the hazard BEFORE the call: it is
|
|
14
|
+
* prompt material, read when the agent is deciding whether to act, not a
|
|
15
|
+
* footnote discovered after.
|
|
16
|
+
*
|
|
17
|
+
* == Authorization is `repo.delete` at either surface
|
|
18
|
+
*
|
|
19
|
+
* The controller authorizes through `RepositoryAuthorization`'s `:repo_delete`
|
|
20
|
+
* fork — deliberately NOT `:owner` — so a member granted `repo.delete` may
|
|
21
|
+
* remove the repository from either surface. The tool does not probe for the
|
|
22
|
+
* capability client-side: the server is the gate, and a member without it
|
|
23
|
+
* receives a 403 whose sentence arrives verbatim through the landed
|
|
24
|
+
* `refusalMessage` branch in `describeFailure`.
|
|
25
|
+
*
|
|
26
|
+
* == 204 with no body
|
|
27
|
+
*
|
|
28
|
+
* This is the one response in the `sgu_` surface that is deliberately not a
|
|
29
|
+
* JSON body — which is why `deleteJson` exists: routing an empty-body 204
|
|
30
|
+
* through `requestJson`'s JSON parse would turn a successful delete into
|
|
31
|
+
* "the body was not JSON". Here, no body IS the success.
|
|
32
|
+
*/
|
|
33
|
+
const removeRepository = {
|
|
34
|
+
name: "remove_repository",
|
|
35
|
+
title: "Remove repository",
|
|
36
|
+
description: "Removes a repository from SpecGuard, DELETING every key, run and intent on it. " +
|
|
37
|
+
"This is IRREVERSIBLE: the repository's CI keys stop authenticating and its recorded " +
|
|
38
|
+
"runs and intents are gone, with no undo and no way to recover them short of " +
|
|
39
|
+
"re-registering from scratch. A 204 means it is deleted. " +
|
|
40
|
+
"Authorization is the `repo.delete` capability at either surface — an owner, or a " +
|
|
41
|
+
"member granted it, may remove the repository; a member without it is refused 403 in " +
|
|
42
|
+
"SpecGuard's own words. Confirm with the user before calling: this is the destructive " +
|
|
43
|
+
"gesture in this toolset, and once it returns 204 the repository and its history " +
|
|
44
|
+
"cannot be brought back. " +
|
|
45
|
+
"Takes `repository_id` — the numeric id `add_repository` and `list_repositories` " +
|
|
46
|
+
"report, not the `org/repo` handle. " +
|
|
47
|
+
"Needs SPECGUARD_USER_API_KEY (an sgu_… key), the same credential `add_repository` " +
|
|
48
|
+
"writes with and a DIFFERENT one from the sgk_… repository key " +
|
|
49
|
+
"`get_repository_overview` uses.",
|
|
50
|
+
inputSchema: {
|
|
51
|
+
type: "object",
|
|
52
|
+
properties: {
|
|
53
|
+
repository_id: {
|
|
54
|
+
type: "string",
|
|
55
|
+
description: "The id of the repository to remove — the numeric id `add_repository` returns " +
|
|
56
|
+
"and `list_repositories` reports, not the `org/repo` handle. SpecGuard scopes " +
|
|
57
|
+
"the lookup to repositories you may act on and answers 404 otherwise.",
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
required: ["repository_id"],
|
|
61
|
+
// Closed for the reason every tool here states: `server.ts` forwards
|
|
62
|
+
// `arguments` unvalidated, and on the DESTRUCTIVE path a silently-dropped
|
|
63
|
+
// argument is the worst case of the write-path argument — the call still
|
|
64
|
+
// deletes something, just not what the agent believed it named.
|
|
65
|
+
additionalProperties: false,
|
|
66
|
+
},
|
|
67
|
+
async run(args, context) {
|
|
68
|
+
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
69
|
+
const api = requireUserApiConfig(context.config);
|
|
70
|
+
const body = await deleteJson(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}`, context.fetch);
|
|
71
|
+
// 204 with no body. Nothing upstream to pass through, so the result says
|
|
72
|
+
// what the verb did — in the tool's own words, because the deployment's
|
|
73
|
+
// whole answer was "no content".
|
|
74
|
+
return {
|
|
75
|
+
text: body === "" ? "Repository removed (204). Every key, run and intent on it is deleted." : body,
|
|
76
|
+
structured: { repository_id: repositoryId, deleted: true },
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
export default removeRepository;
|
|
81
|
+
//# sourceMappingURL=remove-repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-repository.js","sourceRoot":"","sources":["../../../src/tools/remove-repository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,gBAAgB,GAAmB;IACvC,IAAI,EAAE,mBAAmB;IACzB,KAAK,EAAE,mBAAmB;IAC1B,WAAW,EACT,iFAAiF;QACjF,sFAAsF;QACtF,8EAA8E;QAC9E,0DAA0D;QAC1D,mFAAmF;QACnF,sFAAsF;QACtF,uFAAuF;QACvF,kFAAkF;QAClF,0BAA0B;QAC1B,kFAAkF;QAClF,qCAAqC;QACrC,oFAAoF;QACpF,gEAAgE;QAChE,iCAAiC;IACnC,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,+EAA+E;oBAC/E,+EAA+E;oBAC/E,sEAAsE;aACzE;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,CAAC;QAC3B,qEAAqE;QACrE,0EAA0E;QAC1E,yEAAyE;QACzE,gEAAgE;QAChE,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,UAAU,CAC3B,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,EAAE,EAC1D,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,yEAAyE;QACzE,wEAAwE;QACxE,iCAAiC;QACjC,OAAO;YACL,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,uEAAuE,CAAC,CAAC,CAAC,IAAI;YAClG,UAAU,EAAE,EAAE,aAAa,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE;SAC3D,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ToolDefinition } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* `DELETE /api/v1/repositories/:repository_id/api_keys/:id` as a tool —
|
|
4
|
+
* shipped in the platform (`specguard/config/routes.rb:159`,
|
|
5
|
+
* `user_repository_api_keys_controller#destroy`, SPGD-754).
|
|
6
|
+
*
|
|
7
|
+
* == Replacement-mint-then-revoke is the rotation model
|
|
8
|
+
*
|
|
9
|
+
* The platform ships no `#regenerate`. Rotating a compromised key is therefore
|
|
10
|
+
* two calls with tools this slice lands together: mint a replacement
|
|
11
|
+
* (`create_repository_api_key`), deploy it, then revoke the old one here. That
|
|
12
|
+
* ordering is stated in the description because it is the one thing an agent
|
|
13
|
+
* must know before it revokes — revoke-first locks the repository's CI out
|
|
14
|
+
* until a human intervenes.
|
|
15
|
+
*
|
|
16
|
+
* == The id is scoped to the repository
|
|
17
|
+
*
|
|
18
|
+
* `repository.api_keys.find(params[:id])` — a key id belonging to a DIFFERENT
|
|
19
|
+
* repository is a 404, not a cross-repository delete. The bridge relies on that
|
|
20
|
+
* scoping entirely and adds no client-side check of its own, for the reason
|
|
21
|
+
* every tool here states: the server is the gate.
|
|
22
|
+
*
|
|
23
|
+
* == 204 with no body
|
|
24
|
+
*
|
|
25
|
+
* The same empty-body success `remove_repository` serves; the same reason
|
|
26
|
+
* `deleteJson` exists rather than routing a 204 through `requestJson`.
|
|
27
|
+
*/
|
|
28
|
+
declare const revokeRepositoryApiKey: ToolDefinition;
|
|
29
|
+
export default revokeRepositoryApiKey;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { deleteJson, requireUserApiConfig } from "../support/specguard-api.js";
|
|
2
|
+
import { requireString } from "./args.js";
|
|
3
|
+
/**
|
|
4
|
+
* `DELETE /api/v1/repositories/:repository_id/api_keys/:id` as a tool —
|
|
5
|
+
* shipped in the platform (`specguard/config/routes.rb:159`,
|
|
6
|
+
* `user_repository_api_keys_controller#destroy`, SPGD-754).
|
|
7
|
+
*
|
|
8
|
+
* == Replacement-mint-then-revoke is the rotation model
|
|
9
|
+
*
|
|
10
|
+
* The platform ships no `#regenerate`. Rotating a compromised key is therefore
|
|
11
|
+
* two calls with tools this slice lands together: mint a replacement
|
|
12
|
+
* (`create_repository_api_key`), deploy it, then revoke the old one here. That
|
|
13
|
+
* ordering is stated in the description because it is the one thing an agent
|
|
14
|
+
* must know before it revokes — revoke-first locks the repository's CI out
|
|
15
|
+
* until a human intervenes.
|
|
16
|
+
*
|
|
17
|
+
* == The id is scoped to the repository
|
|
18
|
+
*
|
|
19
|
+
* `repository.api_keys.find(params[:id])` — a key id belonging to a DIFFERENT
|
|
20
|
+
* repository is a 404, not a cross-repository delete. The bridge relies on that
|
|
21
|
+
* scoping entirely and adds no client-side check of its own, for the reason
|
|
22
|
+
* every tool here states: the server is the gate.
|
|
23
|
+
*
|
|
24
|
+
* == 204 with no body
|
|
25
|
+
*
|
|
26
|
+
* The same empty-body success `remove_repository` serves; the same reason
|
|
27
|
+
* `deleteJson` exists rather than routing a 204 through `requestJson`.
|
|
28
|
+
*/
|
|
29
|
+
const revokeRepositoryApiKey = {
|
|
30
|
+
name: "revoke_repository_api_key",
|
|
31
|
+
title: "Revoke repository API key",
|
|
32
|
+
description: "Revokes one CI API key on a SpecGuard repository. The key stops authenticating " +
|
|
33
|
+
"immediately; every OTHER key on the repository keeps working, so CI keeps " +
|
|
34
|
+
"ingesting if it holds a surviving key. " +
|
|
35
|
+
"The `key_id` is scoped to `repository_id`: a key id belonging to a different " +
|
|
36
|
+
"repository is refused 404, never a cross-repository delete. " +
|
|
37
|
+
"Key rotation is mint-then-revoke, in that order: the platform has no regenerate, " +
|
|
38
|
+
"so mint a replacement with `create_repository_api_key` and deploy it BEFORE " +
|
|
39
|
+
"revoking the old one — revoke first and the repository's CI is locked out until " +
|
|
40
|
+
"a human mints a new key in a browser. " +
|
|
41
|
+
"Authorization is the `keys_manage` capability — a member without it is refused " +
|
|
42
|
+
"403 in SpecGuard's own words. A 204 means the key is revoked. " +
|
|
43
|
+
"Takes `repository_id` (the numeric id `list_repositories` reports) and `key_id` " +
|
|
44
|
+
"(the id from `add_repository`'s or `create_repository_api_key`'s response). " +
|
|
45
|
+
"Needs SPECGUARD_USER_API_KEY (an sgu_… key), the same credential " +
|
|
46
|
+
"`add_repository` writes with and a DIFFERENT one from the sgk_… repository key " +
|
|
47
|
+
"`get_repository_overview` uses.",
|
|
48
|
+
inputSchema: {
|
|
49
|
+
type: "object",
|
|
50
|
+
properties: {
|
|
51
|
+
repository_id: {
|
|
52
|
+
type: "string",
|
|
53
|
+
description: "The repository the key belongs to — its numeric id, as `add_repository` " +
|
|
54
|
+
"returns and `list_repositories` reports, not the `org/repo` handle.",
|
|
55
|
+
},
|
|
56
|
+
key_id: {
|
|
57
|
+
type: "string",
|
|
58
|
+
description: "The id of the key to revoke, as served in the `api_key` block of " +
|
|
59
|
+
"`add_repository` or `create_repository_api_key` (or the repository's " +
|
|
60
|
+
"API-keys page). Scoped to `repository_id`: a foreign key id is refused 404.",
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
required: ["repository_id", "key_id"],
|
|
64
|
+
// Closed for the reason every tool here states — and on a DESTRUCTIVE path,
|
|
65
|
+
// a silently dropped misspelled argument must not be able to leave the
|
|
66
|
+
// agent believing it revoked a key the call never named.
|
|
67
|
+
additionalProperties: false,
|
|
68
|
+
},
|
|
69
|
+
async run(args, context) {
|
|
70
|
+
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
71
|
+
const keyId = requireString(args["key_id"], "key_id");
|
|
72
|
+
const api = requireUserApiConfig(context.config);
|
|
73
|
+
const body = await deleteJson(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}/api_keys/${encodeURIComponent(keyId)}`, context.fetch);
|
|
74
|
+
// 204 with no body — the tool's own words, because the deployment's whole
|
|
75
|
+
// answer was "no content".
|
|
76
|
+
return {
|
|
77
|
+
text: body === ""
|
|
78
|
+
? `Key ${keyId} revoked (204). Other keys on the repository keep authenticating.`
|
|
79
|
+
: body,
|
|
80
|
+
structured: { repository_id: repositoryId, key_id: keyId, revoked: true },
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
export default revokeRepositoryApiKey;
|
|
85
|
+
//# sourceMappingURL=revoke-repository-api-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revoke-repository-api-key.js","sourceRoot":"","sources":["../../../src/tools/revoke-repository-api-key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,sBAAsB,GAAmB;IAC7C,IAAI,EAAE,2BAA2B;IACjC,KAAK,EAAE,2BAA2B;IAClC,WAAW,EACT,iFAAiF;QACjF,4EAA4E;QAC5E,yCAAyC;QACzC,+EAA+E;QAC/E,8DAA8D;QAC9D,mFAAmF;QACnF,8EAA8E;QAC9E,kFAAkF;QAClF,wCAAwC;QACxC,iFAAiF;QACjF,gEAAgE;QAChE,kFAAkF;QAClF,8EAA8E;QAC9E,mEAAmE;QACnE,iFAAiF;QACjF,iCAAiC;IACnC,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,0EAA0E;oBAC1E,qEAAqE;aACxE;YACD,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,mEAAmE;oBACnE,uEAAuE;oBACvE,6EAA6E;aAChF;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,MAAM,IAAI,GAAG,MAAM,UAAU,CAC3B,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,aAAa,kBAAkB,CAAC,KAAK,CAAC,EAAE,EAChG,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,0EAA0E;QAC1E,2BAA2B;QAC3B,OAAO;YACL,IAAI,EACF,IAAI,KAAK,EAAE;gBACT,CAAC,CAAC,OAAO,KAAK,mEAAmE;gBACjF,CAAC,CAAC,IAAI;YACV,UAAU,EAAE,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE;SAC1E,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|