specguard-mcp 0.1.17 → 0.1.19
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 +105 -47
- package/dist/src/tools/add-repository-member.js +16 -6
- package/dist/src/tools/add-repository-member.js.map +1 -1
- package/dist/src/tools/create-repository-api-key.js +13 -5
- package/dist/src/tools/create-repository-api-key.js.map +1 -1
- package/dist/src/tools/list-repository-agent-keys-presented-revoked.js +12 -4
- package/dist/src/tools/list-repository-agent-keys-presented-revoked.js.map +1 -1
- package/dist/src/tools/list-repository-agent-keys.js +12 -4
- package/dist/src/tools/list-repository-agent-keys.js.map +1 -1
- package/dist/src/tools/list-repository-members.js +11 -5
- package/dist/src/tools/list-repository-members.js.map +1 -1
- package/dist/src/tools/near-duplicate-clusters.d.ts +12 -8
- package/dist/src/tools/near-duplicate-clusters.js +39 -27
- package/dist/src/tools/near-duplicate-clusters.js.map +1 -1
- package/dist/src/tools/remove-repository-member.js +11 -4
- package/dist/src/tools/remove-repository-member.js.map +1 -1
- package/dist/src/tools/repository-overview.d.ts +13 -8
- package/dist/src/tools/repository-overview.js +47 -28
- package/dist/src/tools/repository-overview.js.map +1 -1
- package/dist/src/tools/revoke-repository-agent-key.js +12 -4
- package/dist/src/tools/revoke-repository-agent-key.js.map +1 -1
- package/dist/src/tools/revoke-repository-api-key.js +11 -5
- package/dist/src/tools/revoke-repository-api-key.js.map +1 -1
- package/dist/src/tools/update-repository-member-permissions.js +13 -4
- package/dist/src/tools/update-repository-member-permissions.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,8 +34,8 @@ 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`, `near_duplicate_clusters` (default calls) | — | an agent/CI API key (`sgk_…`) issued by that deployment — a **per-repository** key, which is the single repository those tools answer about by default |
|
|
37
|
-
| `SPECGUARD_USER_API_KEY` | `list_repositories` (fallback), `add_repository`, `registrable_repositories`, `remove_repository` (fallback), `create_repository_api_key
|
|
38
|
-
| `SPECGUARD_AGENT_API_KEY` | `list_repositories` (preferred), `remove_repository` (preferred), `get_repository_overview` / `near_duplicate_clusters` **with** `repository` | — | an **agent** API key (`sga_…`), minted from that deployment's account page (Agent keys panel) with an explicit set of repositories and permissions. It speaks for nobody: its reach is exactly the set granted onto it, fixed at mint time, and every read is bounded by that set server-side. This is the credential to give an automated agent — one key, many repositories, none of a person's rights. When it and `SPECGUARD_USER_API_KEY` are both set, `list_repositories` and `
|
|
37
|
+
| `SPECGUARD_USER_API_KEY` | `list_repositories` (fallback), `add_repository`, `registrable_repositories`, `remove_repository` (fallback), `create_repository_api_key` (fallback), `revoke_repository_api_key` (fallback), `list_repository_agent_keys` (fallback), `revoke_repository_agent_key` (fallback), `list_repository_agent_keys_presented_revoked` (fallback), `list_repository_members` (fallback), `add_repository_member` (fallback), `update_repository_member_permissions` (fallback), `remove_repository_member` (fallback), `get_repository_overview` / `near_duplicate_clusters` **with** `repository` (fallback), `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
|
+
| `SPECGUARD_AGENT_API_KEY` | `list_repositories` (preferred), `remove_repository` (preferred), `create_repository_api_key` (preferred), `revoke_repository_api_key` (preferred), `list_repository_agent_keys` (preferred), `revoke_repository_agent_key` (preferred), `list_repository_agent_keys_presented_revoked` (preferred), `list_repository_members` (preferred), `add_repository_member` (preferred), `update_repository_member_permissions` (preferred), `remove_repository_member` (preferred), `get_repository_overview` / `near_duplicate_clusters` **with** `repository` (preferred) | — | an **agent** API key (`sga_…`), minted from that deployment's account page (Agent keys panel) with an explicit set of repositories and permissions. It speaks for nobody: its reach is exactly the set granted onto it, fixed at mint time, and every read is bounded by that set server-side. This is the credential to give an automated agent — one key, many repositories, none of a person's rights. When it and `SPECGUARD_USER_API_KEY` are both set, every tool that answers either key — `list_repositories`, `remove_repository`, the members tools, the key-lifecycle tools, and `get_repository_overview` / `near_duplicate_clusters` **with** `repository` — uses **this** one, so discovery stays inside the set the other tools can reach |
|
|
39
39
|
| `SPECGUARD_LINT_COMMAND` | `lint_intent_annotations` | `specguard-lint` | the command that runs the linter. Most Ruby projects need `bundle exec specguard-lint` |
|
|
40
40
|
| `SPECGUARD_TIMEOUT_MS` | HTTP tools | `30000` | how long a call to SpecGuard may take |
|
|
41
41
|
|
|
@@ -106,24 +106,29 @@ branch window rather than between the last two runs.
|
|
|
106
106
|
Everything above is answered about **one repository**, and which one has two spellings. By default
|
|
107
107
|
it is the repository the configured `sgk_…` key resolves to — the key *is* the subject. Pass
|
|
108
108
|
`repository` (the numeric id `list_repositories` reports) and the call goes to the **plural**
|
|
109
|
-
endpoint, `GET /api/v1/repositories/:id`,
|
|
110
|
-
`sga_…`)
|
|
109
|
+
endpoint, `GET /api/v1/repositories/:id`, which answers **either member credential**, whichever is
|
|
110
|
+
set: `SPECGUARD_AGENT_API_KEY` (`sga_…`) — preferred, and the set of repositories granted onto it
|
|
111
|
+
at mint time is the boundary ids are looked up inside (`list_repositories` under the same key lists
|
|
112
|
+
exactly the set that is reachable) — or, when no agent key is set, `SPECGUARD_USER_API_KEY`
|
|
113
|
+
(`sgu_…`), a **person** key whose accessible set is the boundary instead. With both set the agent
|
|
114
|
+
key wins, so the answer stays inside the set that key can act on. Same overview body, same ladder,
|
|
115
|
+
every parameter below honoured identically — with one
|
|
111
116
|
deliberate omission this path owns: `api_key` is **absent** from the plural body rather than nulled,
|
|
112
|
-
because that block describes the credential that made the request and
|
|
113
|
-
|
|
117
|
+
because that block describes the credential that made the request and no member credential is a
|
|
118
|
+
repository key (an absent key there is the surface's shape, never a dropped block). Other
|
|
114
119
|
than that, only the subject moves. That is what makes the *other* repositories visible: an `sgk_`
|
|
115
120
|
key is one repository
|
|
116
|
-
by design, so
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
`list_repositories` under the same key lists the set that is reachable). SpecGuard refuses each
|
|
121
|
+
by design, so a credential holding only that could never ask about a second one. The server owns
|
|
122
|
+
every refusal on the plural path: a repository outside the presented credential's grant answers
|
|
123
|
+
404, indistinguishable from one that does not exist, person and agent alike. SpecGuard refuses each
|
|
120
124
|
credential kind in the other's place before it reads anything, so the pairing is not mixable: the
|
|
121
|
-
default call wants the `sgk_` key, the `repository` call wants
|
|
122
|
-
the wrong
|
|
125
|
+
default call wants the `sgk_` key, the `repository` call wants a member key — and a call made with
|
|
126
|
+
the wrong kind, or with neither member key set, is refused *here*, naming the variable(s) to set,
|
|
127
|
+
before any request is made.
|
|
123
128
|
|
|
124
129
|
| argument | |
|
|
125
130
|
| --- | --- |
|
|
126
|
-
| `repository` | ask about THIS repository (its numeric id from `list_repositories`) under the **agent key
|
|
131
|
+
| `repository` | ask about THIS repository (its numeric id from `list_repositories`) under the **agent key** (`SPECGUARD_AGENT_API_KEY`, `sga_…`), or — when no agent key is set — the **user key** (`SPECGUARD_USER_API_KEY`, `sgu_…`), instead of the one the `sgk_…` key resolves to — omit it for the default, `sgk_`-keyed call |
|
|
127
132
|
| `branch` | narrow the run **history** to one branch, for a real growth series — and unlock `unstable_tests` and `directory_growth`, which read the same window |
|
|
128
133
|
| `spec_directory` | open ONE of the heaviest directories and list the spec files inside it |
|
|
129
134
|
| `spec_file` | open ONE of the heaviest spec files and list the individual examples inside it |
|
|
@@ -410,7 +415,8 @@ never used.
|
|
|
410
415
|
Registering a repository is `add_repository`, below — it reads `SPECGUARD_USER_API_KEY` (an
|
|
411
416
|
`sgu_…` key, which this tool also accepts but does not require) and takes the `full_name` this
|
|
412
417
|
tool reports. Removal and the key lifecycle (`remove_repository`,
|
|
413
|
-
`create_repository_api_key`, `revoke_repository_api_key`) are below too, on the same
|
|
418
|
+
`create_repository_api_key`, `revoke_repository_api_key`) are below too, on the same
|
|
419
|
+
either-credential rule; a tool
|
|
414
420
|
here is a promise the agent will act on, so each waits for the capability rather than the other way
|
|
415
421
|
round.
|
|
416
422
|
|
|
@@ -514,13 +520,16 @@ every run; one call returns them all. (The server reads only that the `near_dupl
|
|
|
514
520
|
|
|
515
521
|
| argument | |
|
|
516
522
|
| --- | --- |
|
|
517
|
-
| `repository` | census THIS repository (its numeric id from `list_repositories`) under the **agent key** (`SPECGUARD_AGENT_API_KEY`, `sga_…`), instead of the one the `sgk_…` key resolves to — omit it for the default, `sgk_`-keyed census |
|
|
523
|
+
| `repository` | census THIS repository (its numeric id from `list_repositories`) under the **agent key** (`SPECGUARD_AGENT_API_KEY`, `sga_…`), or — when no agent key is set — the **user key** (`SPECGUARD_USER_API_KEY`, `sgu_…`), instead of the one the `sgk_…` key resolves to — omit it for the default, `sgk_`-keyed census |
|
|
518
524
|
|
|
519
525
|
The credential changes with `repository`, exactly as on `get_repository_overview`: the plural
|
|
520
|
-
endpoint answers
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
526
|
+
endpoint answers **either member credential**, whichever is set — the agent key preferred (its
|
|
527
|
+
mint-time granted repository set is the boundary the id is looked up inside), the user key when no
|
|
528
|
+
agent key is set (its accessible set is the boundary instead), the agent key winning when both are
|
|
529
|
+
present — and the credential kinds refuse each other's tokens, so a
|
|
530
|
+
`repository` ask with neither member key set is refused *here*, naming both variables, before any
|
|
531
|
+
request is made. A repository outside the presented credential's grant answers 404 at the server,
|
|
532
|
+
person and agent alike.
|
|
524
533
|
|
|
525
534
|
Read the response with its own rules in mind:
|
|
526
535
|
|
|
@@ -543,9 +552,9 @@ Read the response with its own rules in mind:
|
|
|
543
552
|
Without `repository`, same credential and endpoint as `get_repository_overview`'s default
|
|
544
553
|
(`sgk_…` repository key on `GET /api/v1/repository`); the response is that body with the
|
|
545
554
|
`near_duplicates` block opened, passed through unmodified. With `repository`, the plural endpoint
|
|
546
|
-
answers
|
|
547
|
-
one deliberate omission: `api_key` is **absent** from the plural body rather than nulled,
|
|
548
|
-
the block describes the credential that made the request and
|
|
555
|
+
answers either member credential, exactly as on `get_repository_overview` — and carries that
|
|
556
|
+
path's one deliberate omission: `api_key` is **absent** from the plural body rather than nulled,
|
|
557
|
+
because the block describes the credential that made the request and no member credential is a
|
|
549
558
|
repository key (an absent key there is the surface's shape, never a dropped block).
|
|
550
559
|
|
|
551
560
|
### `remove_repository`
|
|
@@ -592,9 +601,15 @@ The body comes back as SpecGuard serves it: an `api_key` block (`name`, `token`,
|
|
|
592
601
|
Authorization is the `keys_manage` capability; a member without it is refused `403` with SpecGuard's
|
|
593
602
|
own sentence, verbatim.
|
|
594
603
|
|
|
595
|
-
It reads
|
|
596
|
-
|
|
597
|
-
|
|
604
|
+
It reads either of two credentials, whichever is set — and a different one from the `sgk_…` key
|
|
605
|
+
`get_repository_overview` uses. `SPECGUARD_AGENT_API_KEY` (`sga_…`) when it is set: the call then
|
|
606
|
+
reaches only the repositories granted onto that key at mint time, and only where the grant carries
|
|
607
|
+
`keys.manage` — a repository outside that set is answered `404` in SpecGuard's own words.
|
|
608
|
+
`SPECGUARD_USER_API_KEY` (`sgu_…`) when no agent key is set: the same **person** key `add_repository`
|
|
609
|
+
reads. With both set the **agent** key wins, so the mint answers inside the same set
|
|
610
|
+
`list_repositories` reports. Minting under the agent credential attributes the new key to the agent
|
|
611
|
+
key's **owner** (the server's `attributed_user` rule), so minted-key counts keep naming a person
|
|
612
|
+
rather than nobody.
|
|
598
613
|
|
|
599
614
|
### `revoke_repository_api_key`
|
|
600
615
|
|
|
@@ -615,9 +630,13 @@ replacement with `create_repository_api_key` and deploy it BEFORE revoking the o
|
|
|
615
630
|
first and the repository's CI is locked out until a human mints a new key in a browser. A `204`
|
|
616
631
|
means the key is revoked.
|
|
617
632
|
|
|
618
|
-
It reads
|
|
619
|
-
|
|
620
|
-
|
|
633
|
+
It reads either of two credentials, whichever is set — and a different one from the `sgk_…` key
|
|
634
|
+
`get_repository_overview` uses. `SPECGUARD_AGENT_API_KEY` (`sga_…`) when it is set: the call then
|
|
635
|
+
reaches only the repositories granted onto that key at mint time, and only where the grant carries
|
|
636
|
+
`keys.manage` — a repository outside that set is answered `404` in SpecGuard's own words.
|
|
637
|
+
`SPECGUARD_USER_API_KEY` (`sgu_…`) when no agent key is set: the same **person** key `add_repository`
|
|
638
|
+
reads. With both set the **agent** key wins, so the revoke answers inside the same set
|
|
639
|
+
`list_repositories` reports.
|
|
621
640
|
|
|
622
641
|
### `list_repository_agent_keys`
|
|
623
642
|
|
|
@@ -640,8 +659,14 @@ arriving is `list_repository_agent_keys_presented_revoked`'s question.
|
|
|
640
659
|
time and nothing persisted it. Authorization is the `keys_manage` capability; a caller without it
|
|
641
660
|
is refused `403` with SpecGuard's own sentence, verbatim.
|
|
642
661
|
|
|
643
|
-
It reads
|
|
644
|
-
`
|
|
662
|
+
It reads either of two credentials, whichever is set — and a different one from the `sgk_…` key
|
|
663
|
+
`get_repository_overview` uses. `SPECGUARD_AGENT_API_KEY` (`sga_…`) when it is set: the call then
|
|
664
|
+
reaches only the repositories granted onto that key at mint time, and only where the grant carries
|
|
665
|
+
`keys.manage` — a repository outside that set is answered `404` in SpecGuard's own words, so an
|
|
666
|
+
agent credential administers the agent keys covering its own set without a person's `sgu_` key.
|
|
667
|
+
`SPECGUARD_USER_API_KEY` (`sgu_…`) when no agent key is set: the same **person** key `add_repository`
|
|
668
|
+
reads. With both set the **agent** key wins, so the answer stays inside the same set
|
|
669
|
+
`list_repositories` reports.
|
|
645
670
|
|
|
646
671
|
### `revoke_repository_agent_key`
|
|
647
672
|
|
|
@@ -667,8 +692,14 @@ or one already revoked, is refused `404`, never a cross-repository cut. Authoriz
|
|
|
667
692
|
`keys_manage` capability; a caller without it is refused `403` with SpecGuard's own sentence,
|
|
668
693
|
verbatim.
|
|
669
694
|
|
|
670
|
-
It reads
|
|
671
|
-
`
|
|
695
|
+
It reads either of two credentials, whichever is set — and a different one from the `sgk_…` key
|
|
696
|
+
`get_repository_overview` uses. `SPECGUARD_AGENT_API_KEY` (`sga_…`) when it is set: the call then
|
|
697
|
+
reaches only the repositories granted onto that key at mint time, and only where the grant carries
|
|
698
|
+
`keys.manage` — a repository outside that set is answered `404` in SpecGuard's own words, so an
|
|
699
|
+
agent credential can cut one of its own kind without a person's `sgu_` key.
|
|
700
|
+
`SPECGUARD_USER_API_KEY` (`sgu_…`) when no agent key is set: the same **person** key `add_repository`
|
|
701
|
+
reads. With both set the **agent** key wins, so the cut answers inside the same set
|
|
702
|
+
`list_repositories` reports.
|
|
672
703
|
|
|
673
704
|
### `list_repository_agent_keys_presented_revoked`
|
|
674
705
|
|
|
@@ -691,8 +722,14 @@ it as the offboarding having fully taken.
|
|
|
691
722
|
time and nothing persisted it. Authorization is the `keys_manage` capability; a caller without it
|
|
692
723
|
is refused `403` with SpecGuard's own sentence, verbatim.
|
|
693
724
|
|
|
694
|
-
It reads
|
|
695
|
-
`
|
|
725
|
+
It reads either of two credentials, whichever is set — and a different one from the `sgk_…` key
|
|
726
|
+
`get_repository_overview` uses. `SPECGUARD_AGENT_API_KEY` (`sga_…`) when it is set: the call then
|
|
727
|
+
reaches only the repositories granted onto that key at mint time, and only where the grant carries
|
|
728
|
+
`keys.manage` — a repository outside that set is answered `404` in SpecGuard's own words, so an
|
|
729
|
+
agent credential can verify its own offboarding without a person's `sgu_` key.
|
|
730
|
+
`SPECGUARD_USER_API_KEY` (`sgu_…`) when no agent key is set: the same **person** key `add_repository`
|
|
731
|
+
reads. With both set the **agent** key wins, so the triage stays inside the same set
|
|
732
|
+
`list_repositories` reports.
|
|
696
733
|
|
|
697
734
|
### `list_repository_members`
|
|
698
735
|
|
|
@@ -714,9 +751,13 @@ Authorization is the `members.manage` capability: a caller who is not a member i
|
|
|
714
751
|
(the repository's existence stays hidden), and a member without `members.manage` is refused `403`
|
|
715
752
|
with SpecGuard's own sentence, verbatim.
|
|
716
753
|
|
|
717
|
-
It reads
|
|
718
|
-
|
|
719
|
-
|
|
754
|
+
It reads either of two credentials, whichever is set — and a different one from the `sgk_…` key
|
|
755
|
+
`get_repository_overview` uses. `SPECGUARD_AGENT_API_KEY` (`sga_…`) when it is set: the call then
|
|
756
|
+
reaches only the repositories granted onto that key at mint time, and only where the grant carries
|
|
757
|
+
`members.manage` — a repository outside that set is answered `404` in SpecGuard's own words.
|
|
758
|
+
`SPECGUARD_USER_API_KEY` (`sgu_…`) when no agent key is set: the same **person** key `add_repository`
|
|
759
|
+
reads. With both set the **agent** key wins, so the answer stays inside the same set
|
|
760
|
+
`list_repositories` reports.
|
|
720
761
|
|
|
721
762
|
### `add_repository_member`
|
|
722
763
|
|
|
@@ -732,7 +773,8 @@ permissions.
|
|
|
732
773
|
Each resolution failure — nobody has signed in as that handle yet, the account is archived, the
|
|
733
774
|
handle is ambiguous, the handle is not a login — arrives as a **distinguishable** 400 message
|
|
734
775
|
naming the exact next move. The grantor recorded on the membership is always the person behind
|
|
735
|
-
`
|
|
776
|
+
the credential — the one an `sgu_…` key speaks for, or the **owner** of the `sga_…` agent key.
|
|
777
|
+
The server stamps it; no argument can name a different one.
|
|
736
778
|
|
|
737
779
|
On success (`201`) the response carries a `member` block whose **`id` is the membership id**
|
|
738
780
|
(alongside `handle`, `permissions`, `granted_by`, `created_at`) — the identifier
|
|
@@ -740,9 +782,15 @@ On success (`201`) the response carries a `member` block whose **`id` is the mem
|
|
|
740
782
|
`members.manage` capability; a member without it is refused `403` with SpecGuard's own sentence,
|
|
741
783
|
verbatim.
|
|
742
784
|
|
|
743
|
-
It reads
|
|
744
|
-
|
|
745
|
-
|
|
785
|
+
It reads either of two credentials, whichever is set — and a different one from the `sgk_…` key
|
|
786
|
+
`get_repository_overview` uses. `SPECGUARD_AGENT_API_KEY` (`sga_…`) when it is set: the call then
|
|
787
|
+
reaches only the repositories granted onto that key at mint time, and only where the grant carries
|
|
788
|
+
`members.manage` — a repository outside that set is answered `404` in SpecGuard's own words.
|
|
789
|
+
`SPECGUARD_USER_API_KEY` (`sgu_…`) when no agent key is set: the same **person** key `add_repository`
|
|
790
|
+
reads. With both set the **agent** key wins, so the grant answers inside the same set
|
|
791
|
+
`list_repositories` reports. Under the agent credential the grant is bounded twice: the key cannot
|
|
792
|
+
grant a permission it does not itself hold — SpecGuard answers `400` naming the over-reach — and
|
|
793
|
+
the membership is recorded against the key's **owner**.
|
|
746
794
|
|
|
747
795
|
### `update_repository_member_permissions`
|
|
748
796
|
|
|
@@ -766,9 +814,15 @@ ids are scoped to the repository (a foreign id is refused `404`). Authorization
|
|
|
766
814
|
`members.manage` capability; a member without it is refused `403` with SpecGuard's own sentence,
|
|
767
815
|
verbatim.
|
|
768
816
|
|
|
769
|
-
It reads
|
|
770
|
-
|
|
771
|
-
|
|
817
|
+
It reads either of two credentials, whichever is set — and a different one from the `sgk_…` key
|
|
818
|
+
`get_repository_overview` uses. `SPECGUARD_AGENT_API_KEY` (`sga_…`) when it is set: the call then
|
|
819
|
+
reaches only the repositories granted onto that key at mint time, and only where the grant carries
|
|
820
|
+
`members.manage` — a repository outside that set is answered `404` in SpecGuard's own words.
|
|
821
|
+
`SPECGUARD_USER_API_KEY` (`sgu_…`) when no agent key is set: the same **person** key `add_repository`
|
|
822
|
+
reads. With both set the **agent** key wins, so the edit answers inside the same set
|
|
823
|
+
`list_repositories` reports. Under the agent credential the replacement set is bounded twice: the
|
|
824
|
+
key cannot grant a permission it does not itself hold — SpecGuard answers `400` naming the
|
|
825
|
+
over-reach — and the re-stamped grantor is the key's **owner**.
|
|
772
826
|
|
|
773
827
|
### `remove_repository_member`
|
|
774
828
|
|
|
@@ -790,9 +844,13 @@ number on the wire, so pass it as a string, not as a number (see the edit tool a
|
|
|
790
844
|
Authorization is the `members.manage` capability; a member without it is refused `403` with
|
|
791
845
|
SpecGuard's own sentence, verbatim.
|
|
792
846
|
|
|
793
|
-
It reads
|
|
794
|
-
|
|
795
|
-
|
|
847
|
+
It reads either of two credentials, whichever is set — and a different one from the `sgk_…` key
|
|
848
|
+
`get_repository_overview` uses. `SPECGUARD_AGENT_API_KEY` (`sga_…`) when it is set: the call then
|
|
849
|
+
reaches only the repositories granted onto that key at mint time, and only where the grant carries
|
|
850
|
+
`members.manage` — a repository outside that set is answered `404` in SpecGuard's own words.
|
|
851
|
+
`SPECGUARD_USER_API_KEY` (`sgu_…`) when no agent key is set: the same **person** key `add_repository`
|
|
852
|
+
reads. With both set the **agent** key wins, so the revoke answers inside the same set
|
|
853
|
+
`list_repositories` reports.
|
|
796
854
|
|
|
797
855
|
### `rename_repository`
|
|
798
856
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { postJsonObject,
|
|
1
|
+
import { postJsonObject, requireUserOrAgentApiConfig } from "../support/specguard-api.js";
|
|
2
2
|
import { optionalStringArray, requireString } from "./args.js";
|
|
3
3
|
/**
|
|
4
4
|
* `POST /api/v1/repositories/:repository_id/members` as a tool — shipped in the
|
|
@@ -38,8 +38,9 @@ const addRepositoryMember = {
|
|
|
38
38
|
"SpecGuard refuses each of those with its own sentence, and every other resolution failure " +
|
|
39
39
|
"(nobody has signed in as that handle yet, the account is archived, the handle is ambiguous) " +
|
|
40
40
|
"arrives as a distinguishable 400 message naming the exact next move. " +
|
|
41
|
-
"The grantor recorded on the membership is always the person behind
|
|
42
|
-
"key
|
|
41
|
+
"The grantor recorded on the membership is always the person behind the credential — the one " +
|
|
42
|
+
"an sgu_… key speaks for, or the OWNER of the sga_… agent key. The server stamps it, and no " +
|
|
43
|
+
"argument can name a different one. " +
|
|
43
44
|
"On success (201) the response carries a `member` block whose `id` is the MEMBERSHIP id " +
|
|
44
45
|
"(`handle`, `permissions`, `granted_by`, `created_at` alongside) — the very identifier " +
|
|
45
46
|
"`update_repository_member_permissions` and `remove_repository_member` name. The id is not " +
|
|
@@ -53,8 +54,17 @@ const addRepositoryMember = {
|
|
|
53
54
|
"SpecGuard's own words. " +
|
|
54
55
|
"Takes `repository_id` — the numeric id `list_repositories` reports, not the `org/repo` " +
|
|
55
56
|
"handle. " +
|
|
56
|
-
"
|
|
57
|
-
"
|
|
57
|
+
"It authenticates with EITHER of this server's two member-administration credentials, whichever " +
|
|
58
|
+
"is set: SPECGUARD_AGENT_API_KEY (an sga_… key — the call then reaches only the repositories " +
|
|
59
|
+
"granted onto that key at mint time, and only where the grant carries `members.manage`; a " +
|
|
60
|
+
"repository outside that set answers 404 in SpecGuard's own words, never a probe here) and, " +
|
|
61
|
+
"when that is not set, SPECGUARD_USER_API_KEY (an sgu_… key, the same credential " +
|
|
62
|
+
"`add_repository` writes with). With both set the agent key wins, so the grant answers inside " +
|
|
63
|
+
"the same set `list_repositories` reports. Under the agent credential the grant is bounded " +
|
|
64
|
+
"twice: the key cannot grant a permission it does not itself hold (SpecGuard answers 400 " +
|
|
65
|
+
"naming the over-reach), and the membership is recorded against the key's owner. " +
|
|
66
|
+
"Either way it is a DIFFERENT credential from the sgk_… repository key `get_repository_overview` " +
|
|
67
|
+
"uses.",
|
|
58
68
|
inputSchema: {
|
|
59
69
|
type: "object",
|
|
60
70
|
properties: {
|
|
@@ -88,7 +98,7 @@ const addRepositoryMember = {
|
|
|
88
98
|
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
89
99
|
const handle = requireString(args["handle"], "handle");
|
|
90
100
|
const permissions = optionalStringArray(args["permissions"], "permissions");
|
|
91
|
-
const api =
|
|
101
|
+
const api = requireUserOrAgentApiConfig(context.config);
|
|
92
102
|
// Top-level `{handle, permissions}` — the shape the controller permits,
|
|
93
103
|
// matching `add_repository`'s stated rule: this is JSON an agent writes,
|
|
94
104
|
// not a Rails form. `permissions` omitted when absent so the server's own
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-repository-member.js","sourceRoot":"","sources":["../../../src/tools/add-repository-member.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"add-repository-member.js","sourceRoot":"","sources":["../../../src/tools/add-repository-member.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC1F,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,mBAAmB,GAAmB;IAC1C,IAAI,EAAE,uBAAuB;IAC7B,KAAK,EAAE,uBAAuB;IAC9B,WAAW,EACT,4FAA4F;QAC5F,uBAAuB;QACvB,0FAA0F;QAC1F,4FAA4F;QAC5F,8FAA8F;QAC9F,uEAAuE;QACvE,8FAA8F;QAC9F,6FAA6F;QAC7F,qCAAqC;QACrC,yFAAyF;QACzF,wFAAwF;QACxF,4FAA4F;QAC5F,qFAAqF;QACrF,cAAc;QACd,6FAA6F;QAC7F,yFAAyF;QACzF,0FAA0F;QAC1F,0CAA0C;QAC1C,2FAA2F;QAC3F,yBAAyB;QACzB,yFAAyF;QACzF,UAAU;QACV,iGAAiG;QACjG,8FAA8F;QAC9F,2FAA2F;QAC3F,6FAA6F;QAC7F,kFAAkF;QAClF,+FAA+F;QAC/F,4FAA4F;QAC5F,0FAA0F;QAC1F,kFAAkF;QAClF,kGAAkG;QAClG,OAAO;IACT,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,sFAAsF;oBACtF,mFAAmF;oBACnF,uCAAuC;aAC1C;YACD,WAAW,EAAE;gBACX,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACzB,WAAW,EACT,2EAA2E;oBAC3E,mFAAmF;oBACnF,oFAAoF;oBACpF,mBAAmB;aACtB;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,EAAE,QAAQ,CAAC;QACrC,4EAA4E;QAC5E,wEAAwE;QACxE,oCAAoC;QACpC,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,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;QACvD,MAAM,WAAW,GAAG,mBAAmB,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC,CAAC;QAE5E,MAAM,GAAG,GAAG,2BAA2B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAExD,wEAAwE;QACxE,yEAAyE;QACzE,0EAA0E;QAC1E,0EAA0E;QAC1E,uEAAuE;QACvE,MAAM,OAAO,GAAG,MAAM,cAAc,CAClC,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,UAAU,EAClE,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAChE,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,2EAA2E;QAC3E,yDAAyD;QACzD,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,mBAAmB,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { postJsonObject,
|
|
1
|
+
import { postJsonObject, requireUserOrAgentApiConfig } from "../support/specguard-api.js";
|
|
2
2
|
import { optionalString, requireString } from "./args.js";
|
|
3
3
|
/**
|
|
4
4
|
* `POST /api/v1/repositories/:repository_id/api_keys` as a tool — shipped in
|
|
@@ -40,9 +40,17 @@ const createRepositoryApiKey = {
|
|
|
40
40
|
"`name`, which the server defaults when omitted. " +
|
|
41
41
|
"Authorization is the `keys_manage` capability — a member without it is refused 403 " +
|
|
42
42
|
"in SpecGuard's own words. " +
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"`
|
|
43
|
+
"It authenticates with EITHER of this server's two key-administration credentials, whichever " +
|
|
44
|
+
"is set: SPECGUARD_AGENT_API_KEY (an sga_… key — the call then reaches only the repositories " +
|
|
45
|
+
"granted onto that key at mint time, and only where the grant carries `keys.manage`; a " +
|
|
46
|
+
"repository outside that set answers 404 in SpecGuard's own words, never a probe here) and, " +
|
|
47
|
+
"when that is not set, SPECGUARD_USER_API_KEY (an sgu_… key, the same credential " +
|
|
48
|
+
"`add_repository` writes with). With both set the agent key wins, so the mint answers inside " +
|
|
49
|
+
"the same set `list_repositories` reports. Minting under the agent credential attributes the " +
|
|
50
|
+
"new key to the agent key's OWNER (the server's `attributed_user` rule), so minted-key counts " +
|
|
51
|
+
"keep naming a person rather than nobody. " +
|
|
52
|
+
"Either way it is a DIFFERENT credential from the sgk_… repository key " +
|
|
53
|
+
"`get_repository_overview` uses; SpecGuard refuses each in the other's place.",
|
|
46
54
|
inputSchema: {
|
|
47
55
|
type: "object",
|
|
48
56
|
properties: {
|
|
@@ -65,7 +73,7 @@ const createRepositoryApiKey = {
|
|
|
65
73
|
async run(args, context) {
|
|
66
74
|
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
67
75
|
const name = optionalString(args["name"], "name");
|
|
68
|
-
const api =
|
|
76
|
+
const api = requireUserOrAgentApiConfig(context.config);
|
|
69
77
|
// `name` omitted when absent rather than sent as null, so the server's own
|
|
70
78
|
// `ApiKey::DEFAULT_NAME` default applies — this bridge expresses "no
|
|
71
79
|
// preference", it does not choose on the server's behalf.
|
|
@@ -1 +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,
|
|
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,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC1F,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,8FAA8F;QAC9F,8FAA8F;QAC9F,wFAAwF;QACxF,6FAA6F;QAC7F,kFAAkF;QAClF,8FAA8F;QAC9F,8FAA8F;QAC9F,+FAA+F;QAC/F,2CAA2C;QAC3C,wEAAwE;QACxE,8EAA8E;IAChF,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,2BAA2B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAExD,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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getJsonObject,
|
|
1
|
+
import { getJsonObject, requireUserOrAgentApiConfig } from "../support/specguard-api.js";
|
|
2
2
|
import { requireString } from "./args.js";
|
|
3
3
|
/**
|
|
4
4
|
* `GET /api/v1/repositories/:repository_id/agent_keys/presented_revoked` as a
|
|
@@ -53,8 +53,16 @@ const listRepositoryAgentKeysPresentedRevoked = {
|
|
|
53
53
|
"Authorization is the `keys_manage` capability — a caller without it is refused 403 in " +
|
|
54
54
|
"SpecGuard's own words. " +
|
|
55
55
|
"Takes `repository_id` (the numeric id `list_repositories` reports, not the `org/repo` handle). " +
|
|
56
|
-
"
|
|
57
|
-
"
|
|
56
|
+
"It authenticates with EITHER of this server's two key-administration credentials, whichever " +
|
|
57
|
+
"is set: SPECGUARD_AGENT_API_KEY (an sga_… key — the call then reaches only the repositories " +
|
|
58
|
+
"granted onto that key at mint time, and only where the grant carries `keys.manage`; a " +
|
|
59
|
+
"repository outside that set answers 404 in SpecGuard's own words, never a probe here — an " +
|
|
60
|
+
"agent credential verifying its own offboarding needs no person's `sgu_` key to do it) and, " +
|
|
61
|
+
"when that is not set, SPECGUARD_USER_API_KEY (an sgu_… key, the same credential the other " +
|
|
62
|
+
"key-administration tools read). With both set the agent key wins, so the triage stays inside " +
|
|
63
|
+
"the same set `list_repositories` reports. " +
|
|
64
|
+
"Either way it is a DIFFERENT credential from the sgk_… repository key `get_repository_overview` " +
|
|
65
|
+
"uses; SpecGuard refuses each in the other's place.",
|
|
58
66
|
inputSchema: {
|
|
59
67
|
type: "object",
|
|
60
68
|
properties: {
|
|
@@ -72,7 +80,7 @@ const listRepositoryAgentKeysPresentedRevoked = {
|
|
|
72
80
|
},
|
|
73
81
|
async run(args, context) {
|
|
74
82
|
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
75
|
-
const api =
|
|
83
|
+
const api = requireUserOrAgentApiConfig(context.config);
|
|
76
84
|
const body = await getJsonObject(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}/agent_keys/presented_revoked`, {}, context.fetch);
|
|
77
85
|
// Passed through unreshaped, the standing rule (`types.ts`: "A thin client
|
|
78
86
|
// that reshapes its upstream is not thin") — and the empty answer passes
|
|
@@ -1 +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,
|
|
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,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AACzF,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,8FAA8F;QAC9F,8FAA8F;QAC9F,wFAAwF;QACxF,4FAA4F;QAC5F,6FAA6F;QAC7F,4FAA4F;QAC5F,+FAA+F;QAC/F,4CAA4C;QAC5C,kGAAkG;QAClG,oDAAoD;IACtD,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,2BAA2B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAExD,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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getJsonObject,
|
|
1
|
+
import { getJsonObject, requireUserOrAgentApiConfig } from "../support/specguard-api.js";
|
|
2
2
|
import { requireString } from "./args.js";
|
|
3
3
|
/**
|
|
4
4
|
* `GET /api/v1/repositories/:repository_id/agent_keys` as a tool — shipped in
|
|
@@ -51,8 +51,16 @@ const listRepositoryAgentKeys = {
|
|
|
51
51
|
"Authorization is the `keys_manage` capability — a caller without it is refused 403 in " +
|
|
52
52
|
"SpecGuard's own words. " +
|
|
53
53
|
"Takes `repository_id` (the numeric id `list_repositories` reports, not the `org/repo` handle). " +
|
|
54
|
-
"
|
|
55
|
-
"
|
|
54
|
+
"It authenticates with EITHER of this server's two key-administration credentials, whichever " +
|
|
55
|
+
"is set: SPECGUARD_AGENT_API_KEY (an sga_… key — the call then reaches only the repositories " +
|
|
56
|
+
"granted onto that key at mint time, and only where the grant carries `keys.manage`; a " +
|
|
57
|
+
"repository outside that set answers 404 in SpecGuard's own words, never a probe here — an " +
|
|
58
|
+
"agent credential administering the keys it was granted needs no person's `sgu_` key to do " +
|
|
59
|
+
"it) and, when that is not set, SPECGUARD_USER_API_KEY (an sgu_… key, the same credential the " +
|
|
60
|
+
"other key-administration tools read). With both set the agent key wins, so the answer stays " +
|
|
61
|
+
"inside the same set `list_repositories` reports. " +
|
|
62
|
+
"Either way it is a DIFFERENT credential from the sgk_… repository key `get_repository_overview` " +
|
|
63
|
+
"uses; SpecGuard refuses each in the other's place.",
|
|
56
64
|
inputSchema: {
|
|
57
65
|
type: "object",
|
|
58
66
|
properties: {
|
|
@@ -70,7 +78,7 @@ const listRepositoryAgentKeys = {
|
|
|
70
78
|
},
|
|
71
79
|
async run(args, context) {
|
|
72
80
|
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
73
|
-
const api =
|
|
81
|
+
const api = requireUserOrAgentApiConfig(context.config);
|
|
74
82
|
const body = await getJsonObject(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}/agent_keys`, {}, context.fetch);
|
|
75
83
|
// Passed through unreshaped, the standing rule (`types.ts`: "A thin client
|
|
76
84
|
// that reshapes its upstream is not thin") — the rows are the controller's
|
|
@@ -1 +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,
|
|
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,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AACzF,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,8FAA8F;QAC9F,8FAA8F;QAC9F,wFAAwF;QACxF,4FAA4F;QAC5F,4FAA4F;QAC5F,+FAA+F;QAC/F,8FAA8F;QAC9F,mDAAmD;QACnD,kGAAkG;QAClG,oDAAoD;IACtD,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,2BAA2B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAExD,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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getJsonObject,
|
|
1
|
+
import { getJsonObject, requireUserOrAgentApiConfig } from "../support/specguard-api.js";
|
|
2
2
|
import { requireString } from "./args.js";
|
|
3
3
|
/**
|
|
4
4
|
* `GET /api/v1/repositories/:repository_id/members` as a tool — shipped in the
|
|
@@ -46,9 +46,15 @@ const listRepositoryMembers = {
|
|
|
46
46
|
"`members.manage` is refused 403 in SpecGuard's own words. " +
|
|
47
47
|
"Takes `repository_id` — the numeric id `list_repositories` reports, not the `org/repo` " +
|
|
48
48
|
"handle. " +
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"`
|
|
49
|
+
"It authenticates with EITHER of this server's two member-administration credentials, whichever " +
|
|
50
|
+
"is set: SPECGUARD_AGENT_API_KEY (an sga_… key — the call then reaches only the repositories " +
|
|
51
|
+
"granted onto that key at mint time, and only where the grant carries `members.manage`; a " +
|
|
52
|
+
"repository outside that set answers 404 in SpecGuard's own words, never a probe here) and, " +
|
|
53
|
+
"when that is not set, SPECGUARD_USER_API_KEY (an sgu_… key — a PERSON key, which " +
|
|
54
|
+
"`list_repositories` also accepts but does not require). With both set the agent key wins, so " +
|
|
55
|
+
"the answer stays inside the same set `list_repositories` reports. " +
|
|
56
|
+
"Either way it is a DIFFERENT credential from the sgk_… repository key `get_repository_overview` " +
|
|
57
|
+
"uses; SpecGuard refuses each in the other's place.",
|
|
52
58
|
inputSchema: {
|
|
53
59
|
type: "object",
|
|
54
60
|
properties: {
|
|
@@ -66,7 +72,7 @@ const listRepositoryMembers = {
|
|
|
66
72
|
},
|
|
67
73
|
async run(args, context) {
|
|
68
74
|
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
69
|
-
const api =
|
|
75
|
+
const api = requireUserOrAgentApiConfig(context.config);
|
|
70
76
|
const members = await getJsonObject(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}/members`, {}, context.fetch);
|
|
71
77
|
// Passed through unreshaped, the standing rule (`types.ts`: "A thin client
|
|
72
78
|
// that reshapes its upstream is not thin") — five fields per row, four of
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-repository-members.js","sourceRoot":"","sources":["../../../src/tools/list-repository-members.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"list-repository-members.js","sourceRoot":"","sources":["../../../src/tools/list-repository-members.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AACzF,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,qBAAqB,GAAmB;IAC5C,IAAI,EAAE,yBAAyB;IAC/B,KAAK,EAAE,yBAAyB;IAChC,WAAW,EACT,0FAA0F;QAC1F,6FAA6F;QAC7F,iGAAiG;QACjG,2FAA2F;QAC3F,2FAA2F;QAC3F,4DAA4D;QAC5D,wFAAwF;QACxF,4FAA4F;QAC5F,4DAA4D;QAC5D,yFAAyF;QACzF,UAAU;QACV,iGAAiG;QACjG,8FAA8F;QAC9F,2FAA2F;QAC3F,6FAA6F;QAC7F,mFAAmF;QACnF,+FAA+F;QAC/F,oEAAoE;QACpE,kGAAkG;QAClG,oDAAoD;IACtD,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,6EAA6E;oBAC7E,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,2BAA2B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAExD,MAAM,OAAO,GAAG,MAAM,aAAa,CACjC,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,UAAU,EAClE,EAAE,EACF,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,2EAA2E;QAC3E,0EAA0E;QAC1E,wEAAwE;QACxE,oDAAoD;QACpD,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,qBAAqB,CAAC"}
|
|
@@ -31,14 +31,18 @@ import type { ToolDefinition } from "./types.js";
|
|
|
31
31
|
* run, and one call returns them all. What IS choosable, since SPGD-953, is
|
|
32
32
|
* WHICH REPOSITORY is censused: an optional `repository` argument (a numeric id
|
|
33
33
|
* from `list_repositories`) moves the call to the plural endpoint
|
|
34
|
-
* `GET /api/v1/repositories/:id` under
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
34
|
+
* `GET /api/v1/repositories/:id` under either member credential, whichever is
|
|
35
|
+
* set — the AGENT key preferred, and the USER key (a person credential, whose
|
|
36
|
+
* accessible set is the boundary the id is resolved inside) when no agent key
|
|
37
|
+
* is set; SPGD-1106 widened the plural arm from agent-only, on the same
|
|
38
|
+
* agent-wins/user-fallback terms every either-credential tool answers by. Same
|
|
39
|
+
* body (minus the `api_key` block, which is ABSENT on that surface rather than
|
|
40
|
+
* nulled — see `repository-overview.ts` for why the omission is the server's,
|
|
41
|
+
* deliberately), same ask, same cost gate. Without it the request is
|
|
42
|
+
* byte-for-byte the singular, `sgk_`-bound one this tool has always made — and
|
|
43
|
+
* the cost argument above is exactly why the argument is OPTIONAL rather than
|
|
44
|
+
* required: an agent that has only ever had one reachable repository should not
|
|
45
|
+
* be asked to learn a second credential to keep reading it.
|
|
42
46
|
*
|
|
43
47
|
* `near_duplicates: "true"` is built rather than stringified for the same
|
|
44
48
|
* reason `repository-overview.ts` builds its `unannotated_examples` key:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getJsonObject } from "../support/specguard-api.js";
|
|
1
|
+
import { requireApiConfig } from "../config.js";
|
|
2
|
+
import { getJsonObject, requireUserOrAgentApiConfig } from "../support/specguard-api.js";
|
|
3
3
|
import { optionalString } from "./args.js";
|
|
4
4
|
/**
|
|
5
5
|
* `GET /api/v1/repository?near_duplicates=` as a tool — shipped in the
|
|
@@ -33,14 +33,18 @@ import { optionalString } from "./args.js";
|
|
|
33
33
|
* run, and one call returns them all. What IS choosable, since SPGD-953, is
|
|
34
34
|
* WHICH REPOSITORY is censused: an optional `repository` argument (a numeric id
|
|
35
35
|
* from `list_repositories`) moves the call to the plural endpoint
|
|
36
|
-
* `GET /api/v1/repositories/:id` under
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
36
|
+
* `GET /api/v1/repositories/:id` under either member credential, whichever is
|
|
37
|
+
* set — the AGENT key preferred, and the USER key (a person credential, whose
|
|
38
|
+
* accessible set is the boundary the id is resolved inside) when no agent key
|
|
39
|
+
* is set; SPGD-1106 widened the plural arm from agent-only, on the same
|
|
40
|
+
* agent-wins/user-fallback terms every either-credential tool answers by. Same
|
|
41
|
+
* body (minus the `api_key` block, which is ABSENT on that surface rather than
|
|
42
|
+
* nulled — see `repository-overview.ts` for why the omission is the server's,
|
|
43
|
+
* deliberately), same ask, same cost gate. Without it the request is
|
|
44
|
+
* byte-for-byte the singular, `sgk_`-bound one this tool has always made — and
|
|
45
|
+
* the cost argument above is exactly why the argument is OPTIONAL rather than
|
|
46
|
+
* required: an agent that has only ever had one reachable repository should not
|
|
47
|
+
* be asked to learn a second credential to keep reading it.
|
|
44
48
|
*
|
|
45
49
|
* `near_duplicates: "true"` is built rather than stringified for the same
|
|
46
50
|
* reason `repository-overview.ts` builds its `unannotated_examples` key:
|
|
@@ -81,9 +85,10 @@ const nearDuplicateClusters = {
|
|
|
81
85
|
"`near_duplicates: null` on the plain overview. Calling this tool IS the ask; nothing about the " +
|
|
82
86
|
"census is choosable — the clusters are the repository's, computed over every run, and one call " +
|
|
83
87
|
"returns them all. WHICH repository is censused is the one choice there is: pass `repository` " +
|
|
84
|
-
"(a numeric id from `list_repositories`) to census that named repository under
|
|
85
|
-
"
|
|
86
|
-
"the argument
|
|
88
|
+
"(a numeric id from `list_repositories`) to census that named repository under either member " +
|
|
89
|
+
"credential — the agent key preferred, the person key when no agent key is set — or omit it to " +
|
|
90
|
+
"census the repository the configured sgk_… key resolves to, exactly as before the argument " +
|
|
91
|
+
"existed. " +
|
|
87
92
|
"READ THE DISCLOSURE KEYS BEFORE THE COUNT: `similarity_floor` and `similarity_basis` sit FIRST " +
|
|
88
93
|
"in the block and qualify every cluster below them — a cluster count without what 'similar' " +
|
|
89
94
|
"meant is a figure you cannot act on. `truncated: true` means the cluster list was cut at the " +
|
|
@@ -103,16 +108,18 @@ const nearDuplicateClusters = {
|
|
|
103
108
|
"(`recorded_count: 0`), nothing embedded (`identity_count: 0`), nothing alike — are kept " +
|
|
104
109
|
"distinguishable by those counts rather than collapsed into one empty list. " +
|
|
105
110
|
"Same endpoints and credentials as `get_repository_overview`: without `repository`, an " +
|
|
106
|
-
"`sgk_` repository key on `GET /api/v1/repository`; with `repository`,
|
|
107
|
-
"
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
+
"`sgk_` repository key on `GET /api/v1/repository`; with `repository`, EITHER member " +
|
|
112
|
+
"credential, whichever is set, on `GET /api/v1/repositories/:id` — SPECGUARD_AGENT_API_KEY " +
|
|
113
|
+
"(an sga_… agent key, whose mint-time granted repository set bounds the answer) preferred, " +
|
|
114
|
+
"and, when that is not set, SPECGUARD_USER_API_KEY (an sgu_… key — a PERSON key, whose " +
|
|
115
|
+
"accessible set bounds the answer instead); with both set the agent key wins. The server " +
|
|
116
|
+
"owns the refusals on that path: a repository outside the presented credential's grant " +
|
|
117
|
+
"answers 404, person and agent alike. " +
|
|
111
118
|
"The response is the endpoint's full body with the `near_duplicates` block OPENED, passed " +
|
|
112
119
|
"through unmodified — with the one surface difference `get_repository_overview` documents " +
|
|
113
120
|
"for its own `repository` ask: on that plural path the `api_key` block is ABSENT from the " +
|
|
114
|
-
"body rather than nulled (it describes the credential that made the request, and
|
|
115
|
-
"
|
|
121
|
+
"body rather than nulled (it describes the credential that made the request, and no member " +
|
|
122
|
+
"credential is a repository key), so an absent `api_key` there is the surface's shape, never " +
|
|
116
123
|
"a dropped block.",
|
|
117
124
|
inputSchema: {
|
|
118
125
|
type: "object",
|
|
@@ -122,11 +129,14 @@ const nearDuplicateClusters = {
|
|
|
122
129
|
description: "Census THIS repository instead of the one the configured sgk_… key resolves to. The " +
|
|
123
130
|
"value is the repository's NUMERIC ID, exactly as served in `list_repositories` " +
|
|
124
131
|
"entries' `id` — not the `org/repo` handle. " +
|
|
125
|
-
"The credential changes with it
|
|
126
|
-
"
|
|
127
|
-
"
|
|
128
|
-
"
|
|
129
|
-
"
|
|
132
|
+
"The credential changes with it: the call authenticates with EITHER member credential, " +
|
|
133
|
+
"whichever is set — SPECGUARD_AGENT_API_KEY (an sga_… agent key; the set of " +
|
|
134
|
+
"repositories granted onto it at mint time is the boundary the id is resolved " +
|
|
135
|
+
"inside) and, when that is not set, SPECGUARD_USER_API_KEY (an sgu_… key — a PERSON " +
|
|
136
|
+
"key, whose accessible set is the boundary instead); with both set the agent key " +
|
|
137
|
+
"wins. The server owns the refusals on that path: a repository outside the " +
|
|
138
|
+
"presented credential's grant answers 404, indistinguishable from one that does " +
|
|
139
|
+
"not exist — person and agent alike. The census itself is identical on " +
|
|
130
140
|
"either path: same block, same caps, same disclosure keys. " +
|
|
131
141
|
"Omit it — or pass a blank — and the call is byte-for-byte the singular one under " +
|
|
132
142
|
"SPECGUARD_API_KEY, exactly as before this argument existed.",
|
|
@@ -140,10 +150,12 @@ const nearDuplicateClusters = {
|
|
|
140
150
|
// for the reason `repository-overview.ts` states at its own call site: the
|
|
141
151
|
// pair (path, credential) must not be mixable, because either mixed pairing
|
|
142
152
|
// is a 401 at the deployment by design and both are refused here, legibly,
|
|
143
|
-
// instead.
|
|
153
|
+
// instead. The plural arm answers either member credential — the agent key
|
|
154
|
+
// preferred, the user key when no agent key is set (SPGD-1106) — and the
|
|
155
|
+
// singular arm is unchanged.
|
|
144
156
|
const api = repository === undefined
|
|
145
157
|
? requireApiConfig(context.config)
|
|
146
|
-
:
|
|
158
|
+
: requireUserOrAgentApiConfig(context.config);
|
|
147
159
|
const path = repository === undefined
|
|
148
160
|
? "/api/v1/repository"
|
|
149
161
|
: `/api/v1/repositories/${encodeURIComponent(repository)}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"near-duplicate-clusters.js","sourceRoot":"","sources":["../../../src/tools/near-duplicate-clusters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"near-duplicate-clusters.js","sourceRoot":"","sources":["../../../src/tools/near-duplicate-clusters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AACzF,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AACH,MAAM,qBAAqB,GAAmB;IAC5C,IAAI,EAAE,yBAAyB;IAE/B,KAAK,EAAE,yBAAyB;IAEhC,WAAW,EACT,2FAA2F;QAC3F,gGAAgG;QAChG,gGAAgG;QAChG,gCAAgC;QAChC,kGAAkG;QAClG,iGAAiG;QACjG,gGAAgG;QAChG,iGAAiG;QACjG,iGAAiG;QACjG,+FAA+F;QAC/F,8FAA8F;QAC9F,gGAAgG;QAChG,6FAA6F;QAC7F,WAAW;QACX,iGAAiG;QACjG,6FAA6F;QAC7F,+FAA+F;QAC/F,gGAAgG;QAChG,8DAA8D;QAC9D,iGAAiG;QACjG,8FAA8F;QAC9F,iGAAiG;QACjG,iGAAiG;QACjG,oGAAoG;QACpG,2FAA2F;QAC3F,mGAAmG;QACnG,8FAA8F;QAC9F,2BAA2B;QAC3B,6FAA6F;QAC7F,iFAAiF;QACjF,0FAA0F;QAC1F,6EAA6E;QAC7E,wFAAwF;QACxF,sFAAsF;QACtF,4FAA4F;QAC5F,4FAA4F;QAC5F,wFAAwF;QACxF,0FAA0F;QAC1F,wFAAwF;QACxF,uCAAuC;QACvC,2FAA2F;QAC3F,2FAA2F;QAC3F,2FAA2F;QAC3F,4FAA4F;QAC5F,8FAA8F;QAC9F,kBAAkB;IAEpB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,sFAAsF;oBACtF,iFAAiF;oBACjF,6CAA6C;oBAC7C,wFAAwF;oBACxF,6EAA6E;oBAC7E,+EAA+E;oBAC/E,qFAAqF;oBACrF,kFAAkF;oBAClF,4EAA4E;oBAC5E,iFAAiF;oBACjF,wEAAwE;oBACxE,4DAA4D;oBAC5D,mFAAmF;oBACnF,6DAA6D;aAChE;SACF;QACD,oBAAoB,EAAE,KAAK;KAC5B;IAED,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO;QACrB,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,CAAC;QACpE,4EAA4E;QAC5E,2EAA2E;QAC3E,4EAA4E;QAC5E,2EAA2E;QAC3E,2EAA2E;QAC3E,yEAAyE;QACzE,6BAA6B;QAC7B,MAAM,GAAG,GACP,UAAU,KAAK,SAAS;YACtB,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,CAAC;YAClC,CAAC,CAAC,2BAA2B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAClD,MAAM,IAAI,GACR,UAAU,KAAK,SAAS;YACtB,CAAC,CAAC,oBAAoB;YACtB,CAAC,CAAC,wBAAwB,kBAAkB,CAAC,UAAU,CAAC,EAAE,CAAC;QAE/D,MAAM,QAAQ,GAAG,MAAM,aAAa,CAClC,GAAG,EACH,IAAI,EACJ;YACE,uEAAuE;YACvE,mEAAmE;YACnE,kDAAkD;YAClD,eAAe,EAAE,MAAM;SACxB,EACD,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;YACvC,UAAU,EAAE,QAAQ;SACrB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { deleteJson,
|
|
1
|
+
import { deleteJson, requireUserOrAgentApiConfig } from "../support/specguard-api.js";
|
|
2
2
|
import { requireString } from "./args.js";
|
|
3
3
|
/**
|
|
4
4
|
* `DELETE /api/v1/repositories/:repository_id/members/:id` as a tool — shipped
|
|
@@ -52,8 +52,15 @@ const removeRepositoryMember = {
|
|
|
52
52
|
"SpecGuard's own words. A 204 means the membership is revoked. " +
|
|
53
53
|
"Takes `repository_id` — the numeric id `list_repositories` reports, not the `org/repo` " +
|
|
54
54
|
"handle. " +
|
|
55
|
-
"
|
|
56
|
-
"
|
|
55
|
+
"It authenticates with EITHER of this server's two member-administration credentials, whichever " +
|
|
56
|
+
"is set: SPECGUARD_AGENT_API_KEY (an sga_… key — the call then reaches only the repositories " +
|
|
57
|
+
"granted onto that key at mint time, and only where the grant carries `members.manage`; a " +
|
|
58
|
+
"repository outside that set answers 404 in SpecGuard's own words, never a probe here) and, " +
|
|
59
|
+
"when that is not set, SPECGUARD_USER_API_KEY (an sgu_… key, the same credential " +
|
|
60
|
+
"`add_repository` writes with). With both set the agent key wins, so the revoke answers inside " +
|
|
61
|
+
"the same set `list_repositories` reports. " +
|
|
62
|
+
"Either way it is a DIFFERENT credential from the sgk_… repository key `get_repository_overview` " +
|
|
63
|
+
"uses.",
|
|
57
64
|
inputSchema: {
|
|
58
65
|
type: "object",
|
|
59
66
|
properties: {
|
|
@@ -81,7 +88,7 @@ const removeRepositoryMember = {
|
|
|
81
88
|
async run(args, context) {
|
|
82
89
|
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
83
90
|
const memberId = requireString(args["member_id"], "member_id");
|
|
84
|
-
const api =
|
|
91
|
+
const api = requireUserOrAgentApiConfig(context.config);
|
|
85
92
|
const body = await deleteJson(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}/members/${encodeURIComponent(memberId)}`, context.fetch);
|
|
86
93
|
// 204 with no body — the tool's own words, because the deployment's whole
|
|
87
94
|
// answer was "no content". The keys asymmetry is restated here because the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remove-repository-member.js","sourceRoot":"","sources":["../../../src/tools/remove-repository-member.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"remove-repository-member.js","sourceRoot":"","sources":["../../../src/tools/remove-repository-member.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AACtF,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,sBAAsB,GAAmB;IAC7C,IAAI,EAAE,0BAA0B;IAChC,KAAK,EAAE,0BAA0B;IACjC,WAAW,EACT,sFAAsF;QACtF,kFAAkF;QAClF,uFAAuF;QACvF,mCAAmC;QACnC,yFAAyF;QACzF,uFAAuF;QACvF,uDAAuD;QACvD,yFAAyF;QACzF,2FAA2F;QAC3F,4FAA4F;QAC5F,iEAAiE;QACjE,2FAA2F;QAC3F,uFAAuF;QACvF,0FAA0F;QAC1F,4FAA4F;QAC5F,6FAA6F;QAC7F,4FAA4F;QAC5F,YAAY;QACZ,2FAA2F;QAC3F,gEAAgE;QAChE,yFAAyF;QACzF,UAAU;QACV,iGAAiG;QACjG,8FAA8F;QAC9F,2FAA2F;QAC3F,6FAA6F;QAC7F,kFAAkF;QAClF,gGAAgG;QAChG,4CAA4C;QAC5C,kGAAkG;QAClG,OAAO;IACT,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,iFAAiF;oBACjF,qEAAqE;aACxE;YACD,SAAS,EAAE;gBACT,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,8EAA8E;oBAC9E,kFAAkF;oBAClF,sEAAsE;oBACtE,iFAAiF;oBACjF,8EAA8E;oBAC9E,iBAAiB;aACpB;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,EAAE,WAAW,CAAC;QACxC,4EAA4E;QAC5E,uEAAuE;QACvE,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;QAC3E,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC,CAAC;QAE/D,MAAM,GAAG,GAAG,2BAA2B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAExD,MAAM,IAAI,GAAG,MAAM,UAAU,CAC3B,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,YAAY,kBAAkB,CAAC,QAAQ,CAAC,EAAE,EAClG,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,0EAA0E;QAC1E,2EAA2E;QAC3E,+DAA+D;QAC/D,OAAO;YACL,IAAI,EACF,IAAI,KAAK,EAAE;gBACT,CAAC,CAAC,cAAc,QAAQ,uDAAuD;oBAC7E,gEAAgE;oBAChE,kDAAkD;gBACpD,CAAC,CAAC,IAAI;YACV,UAAU,EAAE,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE;SAChF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|
|
@@ -44,14 +44,19 @@ import type { ToolDefinition } from "./types.js";
|
|
|
44
44
|
*
|
|
45
45
|
* THE CREDENTIAL MOVES WITH IT, because the endpoints refuse each other's
|
|
46
46
|
* tokens before any table is read: the singular path still authenticates with
|
|
47
|
-
* `SPECGUARD_API_KEY` (`sgk_`, one repository), the plural path
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* granted set server-side)
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
47
|
+
* `SPECGUARD_API_KEY` (`sgk_`, one repository), while the plural path answers
|
|
48
|
+
* with EITHER member credential, whichever is set — `SPECGUARD_AGENT_API_KEY`
|
|
49
|
+
* (`sga_`, the agent credential minted for exactly this: one key, many
|
|
50
|
+
* repositories, each read bounded by the key's own granted set server-side)
|
|
51
|
+
* preferred, and `SPECGUARD_USER_API_KEY` (`sgu_`, a person key whose
|
|
52
|
+
* accessible set is the boundary ids are resolved inside instead) when no
|
|
53
|
+
* agent key is set. With both set the agent key wins, so the plural answer
|
|
54
|
+
* stays inside the same set `list_repositories` reports — scope consistency,
|
|
55
|
+
* not preference. Omitting `repository` is byte-for-byte today's request, and
|
|
56
|
+
* an operator who sets neither member variable never sees this half of the
|
|
57
|
+
* tool exist — the blank-is-no-ask rule every argument here follows covers
|
|
58
|
+
* `repository` too, so a blank value falls back to the singular path rather
|
|
59
|
+
* than sending a guaranteed-404 id.
|
|
55
60
|
*
|
|
56
61
|
* == The response is passed through, not re-modelled
|
|
57
62
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getJsonObject } from "../support/specguard-api.js";
|
|
1
|
+
import { requireApiConfig } from "../config.js";
|
|
2
|
+
import { getJsonObject, requireUserOrAgentApiConfig } from "../support/specguard-api.js";
|
|
3
3
|
import { optionalBoolean, optionalString } from "./args.js";
|
|
4
4
|
/**
|
|
5
5
|
* `GET /api/v1/repository` as a tool — shipped today in the platform
|
|
@@ -46,14 +46,19 @@ import { optionalBoolean, optionalString } from "./args.js";
|
|
|
46
46
|
*
|
|
47
47
|
* THE CREDENTIAL MOVES WITH IT, because the endpoints refuse each other's
|
|
48
48
|
* tokens before any table is read: the singular path still authenticates with
|
|
49
|
-
* `SPECGUARD_API_KEY` (`sgk_`, one repository), the plural path
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* granted set server-side)
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
49
|
+
* `SPECGUARD_API_KEY` (`sgk_`, one repository), while the plural path answers
|
|
50
|
+
* with EITHER member credential, whichever is set — `SPECGUARD_AGENT_API_KEY`
|
|
51
|
+
* (`sga_`, the agent credential minted for exactly this: one key, many
|
|
52
|
+
* repositories, each read bounded by the key's own granted set server-side)
|
|
53
|
+
* preferred, and `SPECGUARD_USER_API_KEY` (`sgu_`, a person key whose
|
|
54
|
+
* accessible set is the boundary ids are resolved inside instead) when no
|
|
55
|
+
* agent key is set. With both set the agent key wins, so the plural answer
|
|
56
|
+
* stays inside the same set `list_repositories` reports — scope consistency,
|
|
57
|
+
* not preference. Omitting `repository` is byte-for-byte today's request, and
|
|
58
|
+
* an operator who sets neither member variable never sees this half of the
|
|
59
|
+
* tool exist — the blank-is-no-ask rule every argument here follows covers
|
|
60
|
+
* `repository` too, so a blank value falls back to the singular path rather
|
|
61
|
+
* than sending a guaranteed-404 id.
|
|
57
62
|
*
|
|
58
63
|
* == The response is passed through, not re-modelled
|
|
59
64
|
*
|
|
@@ -563,13 +568,20 @@ const getRepositoryOverview = {
|
|
|
563
568
|
"with the endpoint: the call goes to GET /api/v1/repositories/:id — the plural surface, " +
|
|
564
569
|
"the same overview body with every parameter above honoured identically, MINUS the " +
|
|
565
570
|
"`api_key` block, which is ABSENT there rather than nulled (it describes the credential " +
|
|
566
|
-
"that made the request, and
|
|
567
|
-
"
|
|
568
|
-
"
|
|
569
|
-
"
|
|
570
|
-
"
|
|
571
|
-
"
|
|
572
|
-
"
|
|
571
|
+
"that made the request, and no member credential is a repository key) — and it " +
|
|
572
|
+
"authenticates with EITHER member credential, whichever is set: SPECGUARD_AGENT_API_KEY " +
|
|
573
|
+
"(an sga_… agent key — the call then reaches only the repositories granted onto that key " +
|
|
574
|
+
"at mint time; a repository outside that set answers 404, deliberately indistinguishable " +
|
|
575
|
+
"from a nonexistent one) and, when that is not set, SPECGUARD_USER_API_KEY (an sgu_… key — " +
|
|
576
|
+
"a PERSON key, whose accessible set is the boundary the id is resolved inside, exactly the " +
|
|
577
|
+
"set `list_repositories` reports under the same key). With both set the agent key wins, so " +
|
|
578
|
+
"the answer stays inside the set that key can act on. The server owns every refusal on this " +
|
|
579
|
+
"path — a repository outside the presented credential's grant answers 404 there, person " +
|
|
580
|
+
"and agent alike; SpecGuard refuses each credential KIND in the other's place, and the " +
|
|
581
|
+
"bridge refuses only the credential-less pairing, naming both member variables in one " +
|
|
582
|
+
"message. Omitting `repository` (or passing a blank) is byte-for-byte today's singular " +
|
|
583
|
+
"request, so an operator who sets neither member variable never sees this half of the tool " +
|
|
584
|
+
"exist. " +
|
|
573
585
|
"Figures are null where CI did not report them — a null is 'not measured', never zero. That " +
|
|
574
586
|
"rule is about NULLS and does not run backwards: a non-null figure is not thereby a " +
|
|
575
587
|
"measurement. A run that reported zero tests serves a real `total_specs: 0` beside " +
|
|
@@ -586,20 +598,25 @@ const getRepositoryOverview = {
|
|
|
586
598
|
"in `list_repositories` entries' `id` — not the `org/repo` handle: the plural endpoint " +
|
|
587
599
|
"looks the id up inside the calling key's own read boundary, and a handle casts to no " +
|
|
588
600
|
"id and answers 404. " +
|
|
589
|
-
"The credential changes with it
|
|
590
|
-
"
|
|
591
|
-
"
|
|
592
|
-
"
|
|
593
|
-
"
|
|
594
|
-
"
|
|
601
|
+
"The credential changes with it: the call authenticates with EITHER member credential, " +
|
|
602
|
+
"whichever is set — SPECGUARD_AGENT_API_KEY (an sga_… agent key; the set of " +
|
|
603
|
+
"repositories granted onto it at mint time is the boundary the id is resolved " +
|
|
604
|
+
"inside, and `list_repositories` under the same key lists exactly the set that is " +
|
|
605
|
+
"reachable) and, when that is not set, SPECGUARD_USER_API_KEY (an sgu_… key — a " +
|
|
606
|
+
"PERSON key, whose accessible set is the boundary instead). With both set the " +
|
|
607
|
+
"agent key wins, so the answer stays inside the set that key can act on. SpecGuard " +
|
|
608
|
+
"refuses each credential KIND in the other's place: a repository outside the " +
|
|
609
|
+
"presented credential's grant answers 404, indistinguishable from one that does " +
|
|
610
|
+
"not exist — person and agent alike. " +
|
|
595
611
|
"Every parameter means the same thing on either path: same ladder, same `run_anchor` " +
|
|
596
612
|
"contract, same overview body with ONE difference this path owns — `api_key` is " +
|
|
597
613
|
"ABSENT from the plural response, not null (the block describes the credential that " +
|
|
598
|
-
"made the request, and
|
|
614
|
+
"made the request, and a member-key caller — agent or person — is not a repository " +
|
|
615
|
+
"key), so its absence " +
|
|
599
616
|
"is the plural surface's shape, never a dropped key. " +
|
|
600
617
|
"Omit it — or pass a blank — and the call is byte-for-byte the singular one: " +
|
|
601
618
|
"SPECGUARD_API_KEY on GET /api/v1/repository, exactly as before this argument " +
|
|
602
|
-
"existed, so an operator who
|
|
619
|
+
"existed, so an operator who sets neither member key is unaffected.",
|
|
603
620
|
},
|
|
604
621
|
branch: {
|
|
605
622
|
type: "string",
|
|
@@ -870,17 +887,19 @@ const getRepositoryOverview = {
|
|
|
870
887
|
// asked explicitly for it not to be. See this file's header.
|
|
871
888
|
const unannotatedExamples = optionalBoolean(args["unannotated_examples"], "unannotated_examples");
|
|
872
889
|
// WHICH ENDPOINT AND WHICH CREDENTIAL is decided here, once, from the one
|
|
873
|
-
// ask: `repository` present means the plural surface under
|
|
890
|
+
// ask: `repository` present means the plural surface under either member
|
|
891
|
+
// credential (the agent key preferred, the user key when no agent key is
|
|
892
|
+
// set — the SPGD-1106 widening; the route has served both since SPGD-952),
|
|
874
893
|
// absent means the singular surface under the `sgk_` slot — byte-for-byte
|
|
875
894
|
// the request this tool made before the argument existed. The two are kept
|
|
876
895
|
// as one branch point rather than spread across the call below, so the
|
|
877
896
|
// pair (path, credential) cannot be mixed: a plural path under the
|
|
878
|
-
// repository key, or a singular path under
|
|
897
|
+
// repository key, or a singular path under a member key, is a 401 at the
|
|
879
898
|
// deployment by design, and both mistakes are refused HERE, legibly,
|
|
880
899
|
// instead.
|
|
881
900
|
const api = repository === undefined
|
|
882
901
|
? requireApiConfig(context.config)
|
|
883
|
-
:
|
|
902
|
+
: requireUserOrAgentApiConfig(context.config);
|
|
884
903
|
const path = repository === undefined
|
|
885
904
|
? "/api/v1/repository"
|
|
886
905
|
: `/api/v1/repositories/${encodeURIComponent(repository)}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository-overview.js","sourceRoot":"","sources":["../../../src/tools/repository-overview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"repository-overview.js","sourceRoot":"","sources":["../../../src/tools/repository-overview.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { deleteJsonObject,
|
|
1
|
+
import { deleteJsonObject, requireUserOrAgentApiConfig } from "../support/specguard-api.js";
|
|
2
2
|
import { requireString } from "./args.js";
|
|
3
3
|
/**
|
|
4
4
|
* `DELETE /api/v1/repositories/:repository_id/agent_keys/:id` as a tool —
|
|
@@ -61,8 +61,16 @@ const revokeRepositoryAgentKey = {
|
|
|
61
61
|
"Authorization is the `keys_manage` capability — a caller without it is refused 403 in " +
|
|
62
62
|
"SpecGuard's own words. " +
|
|
63
63
|
"Takes `repository_id` (the numeric id `list_repositories` reports) and `key_id`. " +
|
|
64
|
-
"
|
|
65
|
-
"
|
|
64
|
+
"It authenticates with EITHER of this server's two key-administration credentials, whichever " +
|
|
65
|
+
"is set: SPECGUARD_AGENT_API_KEY (an sga_… key — the call then reaches only the repositories " +
|
|
66
|
+
"granted onto that key at mint time, and only where the grant carries `keys.manage`; a " +
|
|
67
|
+
"repository outside that set answers 404 in SpecGuard's own words, never a probe here — an " +
|
|
68
|
+
"agent credential revoking one of its own kind needs no person's `sgu_` key to do it) and, " +
|
|
69
|
+
"when that is not set, SPECGUARD_USER_API_KEY (an sgu_… key, the same credential the other " +
|
|
70
|
+
"key-administration tools read). With both set the agent key wins, so the cut answers inside " +
|
|
71
|
+
"the same set `list_repositories` reports. " +
|
|
72
|
+
"Either way it is a DIFFERENT credential from the sgk_… repository key `get_repository_overview` " +
|
|
73
|
+
"uses; SpecGuard refuses each in the other's place.",
|
|
66
74
|
inputSchema: {
|
|
67
75
|
type: "object",
|
|
68
76
|
properties: {
|
|
@@ -89,7 +97,7 @@ const revokeRepositoryAgentKey = {
|
|
|
89
97
|
async run(args, context) {
|
|
90
98
|
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
91
99
|
const keyId = requireString(args["key_id"], "key_id");
|
|
92
|
-
const api =
|
|
100
|
+
const api = requireUserOrAgentApiConfig(context.config);
|
|
93
101
|
// The 200 disclosure body, passed through unreshaped in both halves — the
|
|
94
102
|
// deployment already wrote the confirmation (the stored set, count first),
|
|
95
103
|
// and this is the API's substitute for the web confirm dialog.
|
|
@@ -1 +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,
|
|
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,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC5F,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,8FAA8F;QAC9F,8FAA8F;QAC9F,wFAAwF;QACxF,4FAA4F;QAC5F,4FAA4F;QAC5F,4FAA4F;QAC5F,8FAA8F;QAC9F,4CAA4C;QAC5C,kGAAkG;QAClG,oDAAoD;IACtD,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,2BAA2B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAExD,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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { deleteJson,
|
|
1
|
+
import { deleteJson, requireUserOrAgentApiConfig } from "../support/specguard-api.js";
|
|
2
2
|
import { requireString } from "./args.js";
|
|
3
3
|
/**
|
|
4
4
|
* `DELETE /api/v1/repositories/:repository_id/api_keys/:id` as a tool —
|
|
@@ -42,9 +42,15 @@ const revokeRepositoryApiKey = {
|
|
|
42
42
|
"403 in SpecGuard's own words. A 204 means the key is revoked. " +
|
|
43
43
|
"Takes `repository_id` (the numeric id `list_repositories` reports) and `key_id` " +
|
|
44
44
|
"(the id from `add_repository`'s or `create_repository_api_key`'s response). " +
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"`
|
|
45
|
+
"It authenticates with EITHER of this server's two key-administration credentials, whichever " +
|
|
46
|
+
"is set: SPECGUARD_AGENT_API_KEY (an sga_… key — the call then reaches only the repositories " +
|
|
47
|
+
"granted onto that key at mint time, and only where the grant carries `keys.manage`; a " +
|
|
48
|
+
"repository outside that set answers 404 in SpecGuard's own words, never a probe here) and, " +
|
|
49
|
+
"when that is not set, SPECGUARD_USER_API_KEY (an sgu_… key, the same credential " +
|
|
50
|
+
"`add_repository` writes with). With both set the agent key wins, so the revoke answers inside " +
|
|
51
|
+
"the same set `list_repositories` reports. " +
|
|
52
|
+
"Either way it is a DIFFERENT credential from the sgk_… repository key " +
|
|
53
|
+
"`get_repository_overview` uses; SpecGuard refuses each in the other's place.",
|
|
48
54
|
inputSchema: {
|
|
49
55
|
type: "object",
|
|
50
56
|
properties: {
|
|
@@ -69,7 +75,7 @@ const revokeRepositoryApiKey = {
|
|
|
69
75
|
async run(args, context) {
|
|
70
76
|
const repositoryId = requireString(args["repository_id"], "repository_id");
|
|
71
77
|
const keyId = requireString(args["key_id"], "key_id");
|
|
72
|
-
const api =
|
|
78
|
+
const api = requireUserOrAgentApiConfig(context.config);
|
|
73
79
|
const body = await deleteJson(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}/api_keys/${encodeURIComponent(keyId)}`, context.fetch);
|
|
74
80
|
// 204 with no body — the tool's own words, because the deployment's whole
|
|
75
81
|
// answer was "no content".
|
|
@@ -1 +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,
|
|
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,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AACtF,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,8FAA8F;QAC9F,8FAA8F;QAC9F,wFAAwF;QACxF,6FAA6F;QAC7F,kFAAkF;QAClF,gGAAgG;QAChG,4CAA4C;QAC5C,wEAAwE;QACxE,8EAA8E;IAChF,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,2BAA2B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAExD,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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { patchJsonObject,
|
|
1
|
+
import { patchJsonObject, requireUserOrAgentApiConfig } from "../support/specguard-api.js";
|
|
2
2
|
import { requireString, requireStringArray } from "./args.js";
|
|
3
3
|
/**
|
|
4
4
|
* `PATCH /api/v1/repositories/:repository_id/members/:id` as a tool — shipped
|
|
@@ -49,8 +49,17 @@ const updateRepositoryMemberPermissions = {
|
|
|
49
49
|
"SpecGuard's own words. " +
|
|
50
50
|
"Takes `repository_id` — the numeric id `list_repositories` reports, not the `org/repo` " +
|
|
51
51
|
"handle. " +
|
|
52
|
-
"
|
|
53
|
-
"
|
|
52
|
+
"It authenticates with EITHER of this server's two member-administration credentials, whichever " +
|
|
53
|
+
"is set: SPECGUARD_AGENT_API_KEY (an sga_… key — the call then reaches only the repositories " +
|
|
54
|
+
"granted onto that key at mint time, and only where the grant carries `members.manage`; a " +
|
|
55
|
+
"repository outside that set answers 404 in SpecGuard's own words, never a probe here) and, " +
|
|
56
|
+
"when that is not set, SPECGUARD_USER_API_KEY (an sgu_… key, the same credential " +
|
|
57
|
+
"`add_repository` writes with). With both set the agent key wins, so the edit answers inside " +
|
|
58
|
+
"the same set `list_repositories` reports. Under the agent credential the replacement set is " +
|
|
59
|
+
"bounded twice: the key cannot grant a permission it does not itself hold (SpecGuard answers " +
|
|
60
|
+
"400 naming the over-reach), and the re-stamped grantor is the key's owner. " +
|
|
61
|
+
"Either way it is a DIFFERENT credential from the sgk_… repository key `get_repository_overview` " +
|
|
62
|
+
"uses.",
|
|
54
63
|
inputSchema: {
|
|
55
64
|
type: "object",
|
|
56
65
|
properties: {
|
|
@@ -90,7 +99,7 @@ const updateRepositoryMemberPermissions = {
|
|
|
90
99
|
// caught here — before a write — rather than persisted as a member holding
|
|
91
100
|
// nothing.
|
|
92
101
|
const permissions = requireStringArray(args["permissions"], "permissions");
|
|
93
|
-
const api =
|
|
102
|
+
const api = requireUserOrAgentApiConfig(context.config);
|
|
94
103
|
const updated = await patchJsonObject(api, `/api/v1/repositories/${encodeURIComponent(repositoryId)}/members/${encodeURIComponent(memberId)}`, { permissions }, context.fetch);
|
|
95
104
|
// Unreshaped, the standing rule — the 200 body is this verb's whole answer.
|
|
96
105
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-repository-member-permissions.js","sourceRoot":"","sources":["../../../src/tools/update-repository-member-permissions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"update-repository-member-permissions.js","sourceRoot":"","sources":["../../../src/tools/update-repository-member-permissions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC3F,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAG9D;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,iCAAiC,GAAmB;IACxD,IAAI,EAAE,sCAAsC;IAC5C,KAAK,EAAE,sCAAsC;IAC7C,WAAW,EACT,yFAAyF;QACzF,0FAA0F;QAC1F,8EAA8E;QAC9E,0BAA0B;QAC1B,wFAAwF;QACxF,sFAAsF;QACtF,2FAA2F;QAC3F,6CAA6C;QAC7C,2FAA2F;QAC3F,4FAA4F;QAC5F,2FAA2F;QAC3F,2FAA2F;QAC3F,4FAA4F;QAC5F,yEAAyE;QACzE,2FAA2F;QAC3F,yBAAyB;QACzB,yFAAyF;QACzF,UAAU;QACV,iGAAiG;QACjG,8FAA8F;QAC9F,2FAA2F;QAC3F,6FAA6F;QAC7F,kFAAkF;QAClF,8FAA8F;QAC9F,8FAA8F;QAC9F,8FAA8F;QAC9F,6EAA6E;QAC7E,kGAAkG;QAClG,OAAO;IACT,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,iFAAiF;oBACjF,qEAAqE;aACxE;YACD,SAAS,EAAE;gBACT,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,mFAAmF;oBACnF,oFAAoF;oBACpF,qFAAqF;oBACrF,oFAAoF;oBACpF,oDAAoD;aACvD;YACD,WAAW,EAAE;gBACX,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACzB,WAAW,EACT,kFAAkF;oBAClF,mFAAmF;oBACnF,0CAA0C;aAC7C;SACF;QACD,QAAQ,EAAE,CAAC,eAAe,EAAE,WAAW,EAAE,aAAa,CAAC;QACvD,qEAAqE;QACrE,yEAAyE;QACzE,uEAAuE;QACvE,sBAAsB;QACtB,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,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC,CAAC;QAC/D,0EAA0E;QAC1E,4EAA4E;QAC5E,2EAA2E;QAC3E,WAAW;QACX,MAAM,WAAW,GAAG,kBAAkB,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC,CAAC;QAE3E,MAAM,GAAG,GAAG,2BAA2B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAExD,MAAM,OAAO,GAAG,MAAM,eAAe,CACnC,GAAG,EACH,wBAAwB,kBAAkB,CAAC,YAAY,CAAC,YAAY,kBAAkB,CAAC,QAAQ,CAAC,EAAE,EAClG,EAAE,WAAW,EAAE,EACf,OAAO,CAAC,KAAK,CACd,CAAC;QAEF,4EAA4E;QAC5E,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,iCAAiC,CAAC"}
|