From d766741c10c192aebd40afa59c3329ad5c50a877 Mon Sep 17 00:00:00 2001
From: "stacklok-octosts[bot]"
<327033170+stacklok-octosts[bot]@users.noreply.github.com>
Date: Wed, 21 Oct 2026 21:19:19 +0000
Subject: [PATCH] Refresh enterprise references for v0.23.0
---
.../helm/ai-gateway-operator-crds.mdx | 4 +-
.../reference/helm/ai-gateway-operator.mdx | 20 +-
docs/platform/reference/helm/ai-gateway.mdx | 351 +-
.../reference/helm/connector-gateway.mdx | 111 +-
docs/platform/reference/helm/console.mdx | 4 +-
.../reference/helm/enterprise-manager.mdx | 89 +-
docs/platform/reference/helm/platform.mdx | 47 +-
.../reference/helm/registry-server.mdx | 6 +-
.../reference/helm/toolhive-operator-crds.mdx | 4 +-
.../reference/helm/toolhive-operator.mdx | 12 +-
static/api-specs/connector-gateway-api.json | 136 +-
static/api-specs/enterprise-manager-api.json | 4033 +++++++++++++++--
12 files changed, 4301 insertions(+), 516 deletions(-)
diff --git a/docs/platform/reference/helm/ai-gateway-operator-crds.mdx b/docs/platform/reference/helm/ai-gateway-operator-crds.mdx
index 3e362131..04a1a774 100644
--- a/docs/platform/reference/helm/ai-gateway-operator-crds.mdx
+++ b/docs/platform/reference/helm/ai-gateway-operator-crds.mdx
@@ -12,8 +12,8 @@ Configure the AI Gateway operator CRD chart with these Helm values.
This reference lists values declared in the chart's default `values.yaml`.
Templates can also accept optional settings and inherited `global` values.
-Chart: `stacklok-ai-gateway-operator-crds`. Chart version: `0.22.0`. Generated
-from the platform source at `e71926418e98c7598815d0abf07039d3c1646f21`.
+Chart: `stacklok-ai-gateway-operator-crds`. Chart version: `0.23.0`. Generated
+from the platform source at `v0.23.0`.
## Values
diff --git a/docs/platform/reference/helm/ai-gateway-operator.mdx b/docs/platform/reference/helm/ai-gateway-operator.mdx
index 20875f1a..07739fc0 100644
--- a/docs/platform/reference/helm/ai-gateway-operator.mdx
+++ b/docs/platform/reference/helm/ai-gateway-operator.mdx
@@ -12,8 +12,8 @@ Configure the AI Gateway operator chart with these Helm values.
This reference lists values declared in the chart's default `values.yaml`.
Templates can also accept optional settings and inherited `global` values.
-Chart: `ai-gateway-operator`. Chart version: `0.22.0`. Generated from the
-platform source at `e71926418e98c7598815d0abf07039d3c1646f21`.
+Chart: `ai-gateway-operator`. Chart version: `0.23.0`. Generated from the
+platform source at `v0.23.0`.
## Values
@@ -36,7 +36,7 @@ Container image repository for the AI Gateway operator.
**Type:** `string`
-**Default:** `"0.22.0"`
+**Default:** `"0.23.0"`
Container image tag for the AI Gateway operator, aligned with the platform
release.
@@ -61,7 +61,7 @@ processor image override.
**Type:** `string`
-**Default:** `"0.22.0"`
+**Default:** `"0.23.0"`
Tag for the default AI Gateway main-processor image.
@@ -85,7 +85,7 @@ operator.
**Type:** `string`
-**Default:** `"0.22.0"`
+**Default:** `"0.23.0"`
Tag for the default virtual API key service image.
@@ -117,7 +117,7 @@ Container image repository for the Stacklok Enterprise Presidio Analyzer build.
**Type:** `string`
-**Default:** `"0.22.0"`
+**Default:** `"0.23.0"`
Tag for the Presidio Analyzer image, aligned with the platform release.
@@ -149,7 +149,7 @@ Container image repository for the bundled AI Gateway controller.
**Type:** `string`
-**Default:** `"0.22.0"`
+**Default:** `"0.23.0"`
Tag for the bundled AI Gateway controller image.
@@ -172,7 +172,7 @@ Container image repository for the bundled AI Gateway external processor.
**Type:** `string`
-**Default:** `"0.22.0"`
+**Default:** `"0.23.0"`
Tag for the bundled AI Gateway external processor image.
@@ -195,7 +195,7 @@ Container image repository for the bundled Envoy Gateway deployment.
**Type:** `string`
-**Default:** `"0.22.0"`
+**Default:** `"0.23.0"`
Tag for the bundled Envoy Gateway image.
@@ -207,7 +207,7 @@ Tag for the bundled Envoy Gateway image.
Default value
```yaml
-image-proxy.stacklok.com/proxy/stacklok-enterprise/ghcr.io/stacklok/stacklok-enterprise/envoy-ratelimit:0.22.0
+image-proxy.stacklok.com/proxy/stacklok-enterprise/ghcr.io/stacklok/stacklok-enterprise/envoy-ratelimit:0.23.0
```
diff --git a/docs/platform/reference/helm/ai-gateway.mdx b/docs/platform/reference/helm/ai-gateway.mdx
index 96c1cc19..ee3084fd 100644
--- a/docs/platform/reference/helm/ai-gateway.mdx
+++ b/docs/platform/reference/helm/ai-gateway.mdx
@@ -12,8 +12,8 @@ Configure the AI Gateway inference chart with these Helm values.
This reference lists values declared in the chart's default `values.yaml`.
Templates can also accept optional settings and inherited `global` values.
-Chart: `ai-gateway-v2`. Chart version: `0.22.0`. Generated from the platform
-source at `e71926418e98c7598815d0abf07039d3c1646f21`.
+Chart: `ai-gateway-v2`. Chart version: `0.23.0`. Generated from the platform
+source at `v0.23.0`.
## Values
@@ -105,8 +105,10 @@ Override the full name of the resources
**Default:** `true`
Specifies whether a service account should be created. Sprout uses its
-ServiceAccount only as the identity behind the projected tokens it presents to
-the directory and budgets services — it never calls the Kubernetes API itself.
+ServiceAccount as the identity behind the projected tokens it presents to the
+directory and budgets services. With directory.endpoint set it also reads the
+API server's issuer discovery and JWKS for in-cluster workload trusts, bound to
+system:service-account-issuer-discovery; it makes no other Kubernetes API call.
### `serviceAccount.automount`
@@ -114,10 +116,9 @@ the directory and budgets services — it never calls the Kubernetes API itself.
**Default:** `false`
-Automatically mount a ServiceAccount's API-server credentials. Sprout never
-calls the Kubernetes API, so this stays false; the directory/budgets tokens
-below are separate, audience-bound PROJECTED volumes, not the automounted
-API-server token.
+Automatically mount a ServiceAccount's API-server credentials. Stays false:
+every token Sprout presents, including the API-server token for workload trust
+keys, is a separately PROJECTED volume.
### `serviceAccount.annotations`
@@ -229,17 +230,25 @@ Service.
Default value
```yaml
+claimLabels: []
+groupLabelAttributes: []
headerLabels: []
metrics:
port: 9464
otlp:
enabled: false
endpoint: ''
+ headersSecretRef:
+ key: headers
+ name: ''
insecure: false
+ tracesEndpoint: ''
prometheus:
enabled: false
+spanAttributes: []
tracing:
enabled: false
+ exportTimeoutSeconds: 0
samplingRate: 0
```
@@ -287,6 +296,40 @@ endpoint is set, locally or via global.
Disable TLS on the OTLP connection. Only for a collector reachable over a
private, trusted network.
+### `telemetry.otlp.tracesEndpoint`
+
+**Type:** `string`
+
+**Default:** `""`
+
+Exact URL spans are POSTed to over OTLP/HTTP, with no "/v1/traces" appended, for
+a destination whose ingest route is an exact path (a cost/usage platform's, e.g.
+"https://telemetry.cloudzero.com/v2/telemetry/<sink>"). Traces only:
+metrics keep `endpoint`, and with this set `endpoint` is optional for tracing.
+The URL's scheme decides TLS (`insecure` does not apply to it). Must be http(s)
+with a host and no query or fragment. Needs tracing.enabled. Not composed with
+global.stacklok.telemetry.otlp.
+
+### `telemetry.otlp.headersSecretRef`
+
+**Type:** `object`
+
+**Default:** `{"key":"headers","name":""}`
+
+Secret holding the OTLP export headers for `tracesEndpoint`, as
+`key=value,key2=value2` (an Authorization credential). Mounted as a file and
+read at startup, never rendered into the config. Needs an https
+`tracesEndpoint`, and is refused while OTLP metrics push is on (locally or via
+global.stacklok.telemetry.otlp), because the headers are sent on every OTLP
+signal and the metrics collector would receive the destination's credential.
+`key` defaults to "headers".
+
+```yaml
+Example:
+ headersSecretRef:
+ name: cloudzero-otlp-headers
+```
+
### `telemetry.prometheus.enabled`
**Type:** `bool`
@@ -300,7 +343,7 @@ Expose a pull-scrapeable /metrics route on its own dedicated listener
**Type:** `object`
-**Default:** `{"enabled":false,"samplingRate":0}`
+**Default:** `{"enabled":false,"exportTimeoutSeconds":0,"samplingRate":0}`
Push traces to the SAME OTLP collector as otlp.endpoint above — tracing and
metrics are independent signals sharing one transport. Off by default.
@@ -311,8 +354,8 @@ metrics are independent signals sharing one transport. Off by default.
**Default:** `false`
-Export spans via OTLP. Requires otlp.endpoint to be set (shared with
-metrics.otlp above), independently of otlp.enabled.
+Export spans via OTLP. Requires otlp.endpoint (shared with metrics.otlp above,
+independently of otlp.enabled) or otlp.tracesEndpoint to be set.
### `telemetry.tracing.samplingRate`
@@ -320,10 +363,26 @@ metrics.otlp above), independently of otlp.enabled.
**Default:** `0`
-Root-span sampling ratio (0.0-1.0). A sampled inbound traceparent is always
-honored regardless of this ratio (parent-based sampling). Zero (the default) is
-treated as "sample every root span" — leaving it unset when enabled is true
-doesn't silently sample nothing.
+Sampling ratio (0.0-1.0) for a request with no inbound trace context AND for one
+whose inbound traceparent is unsampled: an edge proxy that samples a fraction of
+traces and forwards the rest as unsampled does not suppress this gateway's
+spans, this ratio decides. A sampled inbound traceparent is always honored. Zero
+(the default) is treated as "sample every request" — leaving it unset when
+enabled is true doesn't silently sample nothing. Lower it only to cut span
+volume; a cost platform fed by these spans then counts that fraction of traffic.
+
+### `telemetry.tracing.exportTimeoutSeconds`
+
+**Type:** `int`
+
+**Default:** `0`
+
+Bound, in seconds, on one OTLP export. Zero keeps the library default (30s).
+Raise it above the destination's worst-case response time: **a destination that
+accepts a batch slower than this deadline can be delivered the same batch
+twice**, with nothing logged, and a platform that counts what it receives then
+double-counts those spans. A larger value trades that for a slower flush on
+shutdown. Needs tracing.enabled.
### `telemetry.metrics`
@@ -347,6 +406,11 @@ observed value folds to "other", which is what keeps an operator-controlled
header from becoming an unbounded-cardinality label. Absent by default: no
header contributes a label.
+`header` may not be a governance or credential header (x-user-id,
+x-platform-groups-v1, x-request-id, authorization, x-api-key, x-goog-api-key):
+the value is the caller's own, so it would put a client-chosen identity on the
+metric. Use `claimLabels` to label the metric with a verified caller claim.
+
```yaml
Example:
headerLabels:
@@ -355,6 +419,103 @@ Example:
permitted: [platform, research]
```
+### `telemetry.claimLabels`
+
+**Type:** `list`
+
+**Default:** `[]`
+
+Verified token claims the token-usage metric carries as labels (telemetryConfig
+.ClaimLabels), so a per-caller token series exists: the `sub` claim as `user_id`
+and the `department` claim as `department` give the same dimensions the Envoy
+plane's claimToHeaders-based labels do. This is the ONE way caller identity
+reaches a metric, and it is token-usage only: no other instrument carries it.
+Absent by default: the metric carries no per-caller label.
+
+The value is read from the signed token after verification, never from a header
+or the body, so a client cannot choose it. A virtual-key caller has no token:
+its `sub` is the key owner's directory id, and any other claim name reads the
+owner's directory group label of that name (it must be in
+`directory.groupLabels`). It never reads the key's own metadata. A claim the
+source does not carry omits the label.
+
+Cost: without `permitted` the claim value passes through (bounded to 256 bytes
+of printable text, otherwise "other"), so a per-user label is one series per
+user per model, provider, token type and cache type, and `user_id` is personal
+data in your metrics store. Set `permitted` to the CLOSED set of values that
+pass through when the claim is a bounded dimension; any other value folds to
+"other". A value with leading or trailing whitespace, or a non-ASCII space, also
+folds to "other". `sub` is unique only within one issuer, so with several
+`auth.issuers` two people can share a `user_id` series; map a claim that is
+unique across them, or use `permitted`. At most 10 `claimLabels` entries.
+`attribute` is snake_case and may not be implementation, model, provider,
+token_type or cache_type, nor a `headerLabels` attribute. A claim that changes
+on every token or session (jti, nonce, sid, at_hash, c_hash) needs `permitted`.
+
+```yaml
+Example:
+ claimLabels:
+ - claim: sub
+ attribute: user_id
+ - claim: department
+ attribute: department
+```
+
+### `telemetry.groupLabelAttributes`
+
+**Type:** `list`
+
+**Default:** `[]`
+
+Remap a directory-resolved group label onto a custom span-attribute name on the
+interaction span, in place of the label's bare name (telemetryConfig
+.GroupLabelAttributes). Unlike `headerLabels` this carries no caller-supplied
+data: it chooses the attribute NAME a directory-resolved value is stamped under,
+never the value, so a caller can never populate one of these attributes. Absent
+by default: every resolved label keeps its own bare name.
+
+Each `label` must appear in `directory.groupLabels`, or the gateway refuses to
+start — a remapping of a label nothing resolves would stamp nothing, forever,
+with no error. The same label may be listed more than once to fan one value out
+to several names; once a label is named at all, its bare name is no longer also
+stamped.
+
+```yaml
+Example:
+ groupLabelAttributes:
+ - label: department
+ attribute: cz.context.department
+```
+
+### `telemetry.spanAttributes`
+
+**Type:** `list`
+
+**Default:** `[]`
+
+Copy a caller-sent request header onto the interaction span under a chosen
+attribute name (telemetryConfig .SpanAttributes), such as the `X-Cz-Context-*`
+headers onto `cz.context.*` for a cost platform that reads its business
+dimensions off span attributes. The VALUE is whatever the client sent (cut to
+256 bytes), so it is an attribution hint and never an identity: a
+directory-resolved or gateway-owned attribute of the same name always wins, and
+a name a group label is also stamped under is refused. Absent by default.
+
+`header` is lower-case (letters, digits and hyphens). Credential and
+personal-data headers (authorization, cookie, x-api-key, x-virtual-key,
+x-user-email, x-forwarded-for and the like, plus the platform's own
+x-stacklok-\* identity headers) are refused, as are attribute names under
+gen_ai., stacklok. and budget. (gen_ai.client.app is the one exception), the
+caller-identity attributes, error.type, a duplicate attribute, and more than 20
+entries. Needs telemetry.tracing.enabled.
+
+```yaml
+Example:
+ spanAttributes:
+ - header: x-cz-context-project
+ attribute: cz.context.project
+```
+
### `resources`
**Type:** `object`
@@ -518,7 +679,32 @@ Example:
**Default:** `{"issuers":[]}`
Trusted OIDC issuers for the JWT authentication path (authConfig.Issuers in
-cmd/sprout/main.go): issuer/audience/bindingClaim/tokenUse/jwksUri.
+cmd/sprout/main.go): issuer/audience/bindingClaim/tokenUse/requiredScope/
+jwksUri. requiredScope is the scope a token from that issuer must carry, written
+exactly as the token's scope claim holds it (for Entra, the short name
+"LLM.Invoke", never "api://<app>/LLM.Invoke"). Set it when the IdP gives
+ID tokens and access tokens the same aud; a token without it is refused 403
+insufficient_scope. Empty means no check. A value with whitespace or a character
+RFC 6749 scope tokens exclude fails startup, as does "://" on an Entra issuer.
+
+Each issuer may also set caBundleRef, the CA bundle that verifies its JWKS
+endpoint's serving certificate when the IdP sits behind a private CA. It is
+added to the system roots for that issuer's fetches only:
+
+```yaml
+caBundleRef:
+ secretRef: { name: corp-idp-ca } # or configMapRef: {name: ...}
+ key: ca.crt # optional, default ca.crt
+```
+
+Set exactly one of secretRef and configMapRef. The shape is
+global.stacklok.primaryIdp.caBundleRef's, with key beside the arm; a key inside
+the arm (enterprise-manager's trustedCABundle shape) is refused. An issuer with
+no caBundleRef whose `issuer` equals global.stacklok.primaryIdp.issuer, ignoring
+trailing slashes, inherits global.stacklok.primaryIdp.caBundleRef, so a
+private-CA IdP is declared once for the whole umbrella. The chart mounts the key
+read-only under /etc/sprout/issuer-ca/<index>/ and renders it as the
+issuer's ca_file.
### `directory.endpoint`
@@ -546,7 +732,10 @@ credential projected.
**Default:** `""`
The `iss` the virtual-key path presents to ResolveIdentity so the directory can
-bind the resolved uid to an issuer and return its groups.
+bind the resolved uid to an issuer and return its groups. The uid is presented
+under the `bindingClaim` of the `auth.issuers` entry with this issuer, or under
+`uid` (Okta's binding) when no entry matches. Do not add an issuer to
+`auth.issuers` only for this lookup: the gateway would also trust its tokens.
### `directory.groupLabels`
@@ -599,6 +788,15 @@ Audience the directory's caller-auth gate expects.
Requested lifetime of the projected token. Minimum 600 — the API server REJECTS
a Pod spec below that floor rather than clamping to it.
+### `directory.workloadTrust.pollInterval`
+
+**Type:** `string`
+
+**Default:** `""`
+
+Snapshot poll interval as a Go duration, e.g. "15s", at least "10s". Empty keeps
+the binary's 30s default.
+
### `budgets.endpoint`
**Type:** `string`
@@ -720,13 +918,14 @@ be an accident.
**Default:** `false`
Enforce directory model access on this gateway. Inference is refused (HTTP 403,
-before any provider call) for a model the caller's grants do not cover, and
-/v1/models lists only the models the caller may use. Both halves fail closed.
-Needs directory.endpoint (the discovery filter dials the directory's
-ResolveModelAccess RPC). Reuses budgets.tokenProjection (its audience must equal
-the receiver's budgets audience) and budgets.caBundle /
-global.webhooks.caBundleSecret for the receiver's token and CA, so it also works
-on a gateway that is deliberately unmetered.
+before any provider call) for a model the caller's grants do not cover, and the
+discovery mounts (/v1/models, /anthropic/v1/models, /v1beta/models) list only
+the models the caller may use. Both halves fail closed. Needs directory.endpoint
+(the discovery filter dials the directory's ResolveModelAccess RPC). Reuses
+budgets.tokenProjection (its audience must equal the receiver's budgets
+audience) and budgets.caBundle / global.webhooks.caBundleSecret for the
+receiver's token and CA, so it also works on a gateway that is deliberately
+unmetered.
### `modelAccess.endpoint`
@@ -737,6 +936,23 @@ on a gateway that is deliberately unmetered.
Receiver base URL, e.g. "https://enterprise-server.toolhive-system:443".
Defaults to budgets.endpoint, which is the same listener.
+### `failureLogs.level`
+
+**Type:** `string`
+
+**Default:** `"warn"`
+
+Severity of structured operational failure records (warn, error, or debug).
+
+### `failureLogs.includeMessage`
+
+**Type:** `bool`
+
+**Default:** `true`
+
+Include a bounded parsed failure message by default. Set false to log metadata
+only when stderr retention or access cannot accommodate PII.
+
### `audit.enabled`
**Type:** `bool`
@@ -875,6 +1091,14 @@ aws_credentials_file (the ambient EKS-Pod-Identity chain), the chart
automatically adds the Pod Identity Agent's link-local egress rule
(169.254.170.23/32 and fd00:ec2::23/128, TCP 80) — no need to list it here.
+Workload trust keys (directory.endpoint set): an in-cluster trust needs the API
+server's endpoint addresses and port, often 6443, which
+`kubectl get endpointslices -n default -l kubernetes.io/service-name=kubernetes`
+lists. Allowing the `kubernetes.default` Service address on 443 is not enough:
+most network plugins evaluate egress after rewriting it to the endpoint. A trust
+with a public JWKS URL needs its host on 443, which the provider rule above
+already admits.
+
### `extraEnv`
**Type:** `list`
@@ -1013,7 +1237,7 @@ adapter:
logLevel: ''
maxReplicas: null
metrics:
- enabled: false
+ enabled: null
port: 9090
nodeSelector: {}
podAnnotations: {}
@@ -1043,7 +1267,6 @@ ner:
circuitBreaker:
failureThreshold: 5
resetTimeout: 30s
- concurrency: 8
failureAction: fail-closed
timeout: 5s
presidio:
@@ -1063,10 +1286,10 @@ presidio:
resources:
limits:
cpu: '2'
- memory: 2Gi
+ memory: 3Gi
requests:
cpu: 500m
- memory: 1Gi
+ memory: 2Gi
scoreThreshold: 50
targetCPUUtilization: null
tolerations: []
@@ -1185,16 +1408,6 @@ How allowlist entries match: `exact` or `regex`.
Budget for one Presidio call, as a single-unit Go duration. Must be positive.
-### `scanning.ner.concurrency`
-
-**Type:** `int`
-
-**Default:** `8`
-
-Concurrent Presidio calls within one request. The adapter scans a request's text
-nodes in waves of this size. It is not a pod-wide cap: every in-flight request
-gets its own limit.
-
### `scanning.ner.failureAction`
**Type:** `string`
@@ -1229,11 +1442,12 @@ How long the breaker stays open before probing again.
Budget the gateway gives the adapter, as a single-unit Go duration. Empty
derives ner.timeout + 2s, so a slow Presidio surfaces the adapter's fail-closed
403 rather than the gateway's own 504. That covers one wave of Presidio calls.
-The adapter has no request-wide deadline, so a request with more than
-ner.concurrency text nodes runs several waves, and a slow Presidio that still
-answers within ner.timeout can push it past this budget into a gateway 504.
-Raise it if large requests need more than one wave under load. An explicit value
-must exceed ner.timeout.
+The adapter has no request-wide deadline, so a request with more Presidio calls
+than presidio.replicas times the workers per pod (more text nodes, or text nodes
+over 50,000 characters, which are scanned in chunks) runs several waves, and a
+slow Presidio that still answers within ner.timeout can push it past this budget
+into a gateway 504. Raise it if large requests need more than one wave under
+load. An explicit value must exceed ner.timeout.
### `scanning.hook.tokenExpirationSeconds`
@@ -1409,13 +1623,17 @@ Adapter log level (`debug|info|warn|error`). Empty keeps the binary default.
### `scanning.adapter.metrics.enabled`
-**Type:** `bool`
+**Type:** `string`
-**Default:** `false`
+**Default:** `nil`
-Serve the adapter's Prometheus metrics on `port`, and admit scrapes to that port
-in its NetworkPolicy from networkPolicy.ingress.monitoringNamespaces (or from
-any source under networkPolicy.ingress.allowAllSources).
+The adapter records what it scans (PII detections, unscanned requests) on its
+own metrics. Unset follows the gateway's telemetry settings:
+telemetry.prometheus.enabled serves them on `port`, admitting scrapes from
+networkPolicy.ingress.monitoringNamespaces (or from any source under
+networkPolicy.ingress.allowAllSources), and OTLP metrics push sends them to the
+same collector. `false` turns both off; `true` serves `port` whatever the
+gateway does.
### `scanning.resultCache.enabled`
@@ -1589,7 +1807,10 @@ Image pull policy.
**Default:** `2`
Replica count. Also the HPA's minReplicas when one renders. A
-PodDisruptionBudget renders at 2 or more.
+PodDisruptionBudget renders at 2 or more. The per-request Presidio fan-out is
+this value times the workers per pod, so with autoscaling.mode External set it
+to the minimum the external scaler keeps, even though the Deployment then omits
+it.
### `scanning.presidio.maxReplicas`
@@ -1663,9 +1884,14 @@ Presidio selector labels into each entry that sets no labelSelector.
**Type:** `object`
**Default:**
-`{"limits":{"cpu":"2","memory":"2Gi"},"requests":{"cpu":"500m","memory":"1Gi"}}`
+`{"limits":{"cpu":"2","memory":"3Gi"},"requests":{"cpu":"500m","memory":"2Gi"}}`
-Analyzer container resources.
+Analyzer container resources. The analyzer runs one worker per whole core of
+limits.cpu (at least 1, and 1 when no CPU limit is set), since one worker
+analyzes one request at a time on one core. Each worker loads its own NER model,
+so size limits.memory at about 1Gi per worker plus headroom: the default 2 cores
+run 2 workers that peak near 2Gi. A memory limit under 1Gi per worker fails the
+render.
### `scanning.presidio.language`
@@ -1996,6 +2222,29 @@ Annotations on the adapter's ServiceAccount, e.g. the
Adapter container resources.
+### `guardrails.adapter.metrics.enabled`
+
+**Type:** `string`
+
+**Default:** `nil`
+
+The adapter records what it screens (deny categories, unscreenable requests) on
+its own metrics. Unset follows the gateway's telemetry settings:
+telemetry.prometheus.enabled serves them on `port`, admitting scrapes from
+networkPolicy.ingress.monitoringNamespaces (or from any source under
+networkPolicy.ingress.allowAllSources), and OTLP metrics push sends them to the
+same collector. `false` turns both off; `true` serves `port` whatever the
+gateway does.
+
+### `guardrails.adapter.metrics.port`
+
+**Type:** `int`
+
+**Default:** `9090`
+
+Port for the guardrails adapter's Prometheus metrics listener when metrics
+serving is enabled.
+
## Related information
- [Platform Helm chart references](./index.mdx)
diff --git a/docs/platform/reference/helm/connector-gateway.mdx b/docs/platform/reference/helm/connector-gateway.mdx
index 58d8dfab..677a2357 100644
--- a/docs/platform/reference/helm/connector-gateway.mdx
+++ b/docs/platform/reference/helm/connector-gateway.mdx
@@ -12,8 +12,8 @@ Configure the Connector Gateway chart with these Helm values.
This reference lists values declared in the chart's default `values.yaml`.
Templates can also accept optional settings and inherited `global` values.
-Chart: `connector-gateway`. Chart version: `0.22.0`. Generated from the platform
-source at `e71926418e98c7598815d0abf07039d3c1646f21`.
+Chart: `connector-gateway`. Chart version: `0.23.0`. Generated from the platform
+source at `v0.23.0`.
## Values
@@ -98,9 +98,10 @@ Override the full name of the resources
**Default:** `true`
-Specifies whether a service account should be created. The gateway's in-cluster
-BackendWatcher authenticates to the API server with this ServiceAccount's token,
-so it is created (and its token mounted) by default.
+Specifies whether a service account should be created. The gateway presents this
+ServiceAccount's token to the API server to verify internalApi callers, and
+projected tokens of it to Directory, metering ingest and enterprise-manager, so
+it is created (and its token mounted) by default.
### `serviceAccount.automount`
@@ -108,8 +109,8 @@ so it is created (and its token mounted) by default.
**Default:** `true`
-Automatically mount a ServiceAccount's API credentials. Required: the
-BackendWatcher reads the MCP backend CRs via the mounted token.
+Automatically mount a ServiceAccount's API credentials. Required: the gateway
+reads the mounted token (see internalApi).
### `serviceAccount.annotations`
@@ -128,19 +129,6 @@ Annotations to add to the service account
The name of the service account to use (if not set and create is true, a name is
generated using the fullname template)
-### `rbac.create`
-
-**Type:** `bool`
-
-**Default:** `true`
-
-Specifies whether RBAC resources should be created: the namespaced Role granting
-the BackendWatcher get/list/watch on the MCP backend CRs and ConfigMaps, plus
-the RoleBinding to the chart's ServiceAccount. The BackendReconciler is
-single-namespace by design, so this is a Role / RoleBinding in
-`.Release.Namespace` — never a ClusterRole. Set to false if you manage RBAC
-externally or bind a pre-existing ServiceAccount.
-
### `podAnnotations`
**Type:** `object`
@@ -281,6 +269,7 @@ exposes it on the same port.
```yaml
allowedSubjects: []
audience: connector-gateway-internal
+deriveEnterpriseManagerSubject: false
enabled: false
issuer: ''
port: 8091
@@ -349,8 +338,26 @@ directory.connectorGateway.tokenAudience must be set to the same value.
ServiceAccount subjects permitted to call, as
system:serviceaccount:<namespace>:<name>. REQUIRED when enabled:
-the chart refuses to render an enabled internal API with none. Include the
-enterprise-manager's ServiceAccount.
+the chart refuses to render an enabled internal API with none. Every subject
+listed here may call both internal routes, so it can revoke any User's stored
+upstream tokens on this gateway as well as list a Connector's tools. Empty
+derives the enterprise-manager's ServiceAccount subject when
+deriveEnterpriseManagerSubject is true. Helm replaces a list whole, so a value
+set here must list the enterprise-manager's subject itself.
+
+### `internalApi.deriveEnterpriseManagerSubject`
+
+**Type:** `bool`
+
+**Default:** `false`
+
+Derive allowedSubjects, when it is empty, from the enterprise-manager installed
+in the same release
+(system:serviceaccount:<namespace>:<release>-enterprise-manager).
+The stacklok-enterprise-platform umbrella sets it, and checks at render time
+that the subject matches the ServiceAccount enterprise-manager actually runs as.
+Leave it false on a standalone install, where no sibling enterprise-manager is
+known, so an empty allowlist is refused rather than admitting a guessed subject.
### `internalApi.issuer`
@@ -613,6 +620,16 @@ the umbrella's global.stacklok.audit (#4409) — see
connector-gateway.effectiveVmcpConfig. Setting `audit` here at all, in any
shape, opts out of that fallback and always wins in full.
+Sections that take effect: name, incomingAuth (its oidc block, when an auth
+server is configured), aggregation, compositeTools, rateLimiting, sessionStorage
+and audit. outgoingAuth.backends/default are cleared at load with a WARN: every
+backend's auth comes from its Directory Connector. backends, compositeToolRefs,
+telemetry, operational, metadata, optimizer, codeMode and passthroughHeaders are
+validated but ignored; OTLP settings go under enterpriseConfig.telemetry. The
+gateway reads no toolhive CRD (MCPServer, MCPGroup, MCPExternalAuthConfig, ...):
+register a backend as a Connector in the Directory instead. See
+docs/design/configuration-sources.md.
+
### `vmcpConfig.groupRef`
**Type:** `string`
@@ -622,6 +639,15 @@ shape, opts out of that fallback and always wins in full.
MCPGroup name backing this gateway, used for status/logging visibility only.
Backends are always read from the directory (enterpriseConfig.directory).
+### `vmcpConfig.outgoingAuth`
+
+**Type:** `object`
+
+**Default:** `{"source":"discovered"}`
+
+outgoingAuth.backends and outgoingAuth.default are ignored (one startup WARN
+when set): every backend's auth comes from its Directory Connector.
+
### `enterpriseConfig`
**Type:** `string`
@@ -671,6 +697,20 @@ clientClaimAllowUnsafe (a real boolean, never --set-string) admits it.
enterpriseConfig.primaryIdp is NOT a door — it is chart-owned and refused at
render, the same as enterpriseConfig.gateway.
+Microsoft Entra ID requires clientClaim: azp. The platform accepts only v2.0
+tokens (issuer https://login.microsoftonline.com/<tenant>/v2.0;
+api.requestedAccessTokenVersion: 2 in the manifest of the app registration that
+exposes the API), which carry the client ID in azp; v1.0 tokens (and their appid
+claim) are not supported. When the platform issuer (the issuer_url of
+authServer.upstreams[0]) is Entra v2.0 (the public, US Government or China cloud
+host) and clientClaim is unset on both doors (an explicit empty
+appConfig.primaryIdp.clientClaim counts as unset), the chart renders
+clientClaim: azp. An explicit claim other than azp on such an issuer fails the
+render. Entra External ID and Azure AD B2C issuers are not recognised, so set
+azp by hand there. Dex emits azp only on a cross-client token (one requested
+with an audience:server:client_id:<peer> scope); a plain Dex token has
+no azp.
+
```yaml
appConfig:
featureFlags:
@@ -1204,14 +1244,15 @@ validated at render to name a version actually present in that map. See
A free-form token that forces a rolling restart when it changes, so phase one of
a rotation reliably rolls out the new keyring even when activeVersion does not
change. It is hashed into the pod checksum alongside kek.value /
-kek.existingSecret / kek.activeVersion. This is REQUIRED in existingSecret mode,
-where the Secret's CONTENT is not part of the checksum: adding a version to the
-external Secret changes nothing the chart can see, and on a second or later
-rotation activeVersion is already pinned to the current version, so phase one
-would otherwise perform no rollout and phase two's single restart would strand
-rows. Bump this (e.g. an incrementing integer, or the delivered Secret's
-resourceVersion) on every phase one. Harmless in value/generate mode, where a
-keyring change already re-hashes the checksum. See
+kek.existingSecret / kek.activeVersion. This is REQUIRED in existingSecret and
+generate mode, where the Secret's CONTENT is not part of the checksum: adding a
+version to the external Secret, or to the chart-managed `-kek` Secret
+that generate mode preserves through `lookup`, changes nothing the chart can
+see. On a second or later rotation activeVersion is already pinned to the
+current version, so phase one would otherwise perform no rollout and phase two's
+single restart would strand rows. Bump this (e.g. an incrementing integer, or
+the delivered Secret's resourceVersion) on every phase one. Harmless in value
+mode, where a keyring change already re-hashes the checksum. See
[Rotate the encryption key](https://docs.stacklok.com/connector-gateway/rotate-encryption-key).
### `authServerKeys`
@@ -1331,11 +1372,11 @@ OVERRIDING any cluster-wide default-deny egress policy (Kyverno
Recommended default nonetheless: every outbound destination this gateway dials
(global.stacklok.primaryIdp.issuer, enterprise-manager's directory gRPC, and
-every MCP backend the BackendWatcher discovers via in-cluster CRs) is
-deployment-specific — this chart has no way to know your actual backends at
-template time, so a fixed allow-list here would be a guess. Set to false and
-populate `egress` below to actually lock this pod down (this gateway holds the
-KEK and the primary-IdP client secret, so this matters more than usual).
+every MCP backend Directory serves) is deployment-specific — this chart has no
+way to know your actual backends at template time, so a fixed allow-list here
+would be a guess. Set to false and populate `egress` below to actually lock this
+pod down (this gateway holds the KEK and the primary-IdP client secret, so this
+matters more than usual).
### `networkPolicy.egress`
diff --git a/docs/platform/reference/helm/console.mdx b/docs/platform/reference/helm/console.mdx
index 5662dcbb..b8ae3865 100644
--- a/docs/platform/reference/helm/console.mdx
+++ b/docs/platform/reference/helm/console.mdx
@@ -11,8 +11,8 @@ Configure the console chart with these Helm values.
This reference lists values declared in the chart's default `values.yaml`.
Templates can also accept optional settings and inherited `global` values.
-Chart: `toolhive-cloud-ui`. Chart version: `0.22.0`. Generated from the platform
-source at `e71926418e98c7598815d0abf07039d3c1646f21`.
+Chart: `toolhive-cloud-ui`. Chart version: `0.23.0`. Generated from the platform
+source at `v0.23.0`.
## Values
diff --git a/docs/platform/reference/helm/enterprise-manager.mdx b/docs/platform/reference/helm/enterprise-manager.mdx
index fb8addc0..17f55049 100644
--- a/docs/platform/reference/helm/enterprise-manager.mdx
+++ b/docs/platform/reference/helm/enterprise-manager.mdx
@@ -12,8 +12,8 @@ Configure the Enterprise Manager chart with these Helm values.
This reference lists values declared in the chart's default `values.yaml`.
Templates can also accept optional settings and inherited `global` values.
-Chart: `enterprise-manager`. Chart version: `0.22.0`. Generated from the
-platform source at `e71926418e98c7598815d0abf07039d3c1646f21`.
+Chart: `enterprise-manager`. Chart version: `0.23.0`. Generated from the
+platform source at `v0.23.0`.
## Values
@@ -1257,8 +1257,11 @@ awsRdsIam:
`{"existingSecret":"","existingSecretKey":"postgres-admin-password","user":""}`
admin: BYPASSRLS credentials for the directory module's admin pool used for
-cross-user connector-config reads (AdminListUserConnectorConfigs). Pre-create a
-Secret with key `postgres-admin-password`, then set existingSecret to its name.
+cross-user reads (AdminListUserConnectorConfigs, the admin Connection reads) and
+for Delete connector, which must read every User's Connections to revoke the
+upstream tokens its cascade orphans. Without it, Delete connector answers 503
+naming database.admin and deletes nothing. Pre-create a Secret with key
+`postgres-admin-password`, then set existingSecret to its name.
PREREQUISITE: the migration user (database.migration.user) must hold SUPERUSER
or CREATEROLE to apply BYPASSRLS to the admin role at boot. On managed Postgres
@@ -1650,6 +1653,7 @@ taxonomy:
```yaml
connectorGateway:
controlPlaneUrl: ''
+ gatewayId: ''
timeout: ''
tokenAudience: connector-gateway-internal
tokenExpirationSeconds: 600
@@ -1712,6 +1716,7 @@ absolute URLs, so set this whenever issuers are configured). Example:
```yaml
controlPlaneUrl: ''
+gatewayId: ''
timeout: ''
tokenAudience: connector-gateway-internal
tokenExpirationSeconds: 600
@@ -1741,7 +1746,27 @@ Origin of the connector-gateway's INTERNAL API listener, not the control-plane
URL the Console uses. E.g.
http://<release>-connector-gateway-internal.<namespace>.svc:8091.
Plain HTTP is accepted in-cluster: the token is audience-bound and short-lived,
-and the response carries tool names only.
+and the requests carry ids and tool names only. Besides tool refresh, it is how
+deleting a Connection revokes the user's orphaned upstream token at the gateway;
+with no url that token stays stored and is reused when the user reconnects.
+
+Empty derives the address of the connector-gateway in the same release when
+global.stacklok.connectorGateway.enabled is true and serviceAccount.create is
+true (the umbrella default): the gateway derives this chart's ServiceAccount
+subject into its internalApi.allowedSubjects. Set it explicitly when the
+gateway's fullnameOverride, nameOverride or internalApi.port differ from their
+defaults.
+
+### `directory.connectorGateway.gatewayId`
+
+**Type:** `string`
+
+**Default:** `""`
+
+Id of the Gateway url reaches. Upstream-token revocation names it in every
+request and needs it to tell a Connection on another Gateway apart. Empty uses
+global.stacklok.connectorGatewayId; with url set and neither, the chart refuses
+to render.
### `directory.connectorGateway.controlPlaneUrl`
@@ -1853,25 +1878,41 @@ namespace: "stacklok" name: "directory-scim-token-okta" key: "token"
group_variables: # SCIM user attributes to mint UserGroups from - "department" #
bare path: label derived from it - path:
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:costCenter" label:
-"cost_center" # label its UserGroups carry group_variables is the only surface
-that enables generated UserGroups: one group per distinct value the attribute
-carries on this issuer's active users, compared with surrounding whitespace
-trimmed and letter case folded, so "Marketing" and "marketing" are one group
-whose membership is the union of both. Membership is kept in step with the user
-table hourly. There is no Admin equivalent — an Admin governs the resulting
-groups but cannot cause them to exist. Paths are written in SCIM attribute path
-notation, so an extension attribute carries its full URN, and a malformed one
-refuses the boot. `label` is the ONE place a label is authored: a SCIM path
-carries schema URNs and camel case, so the label is a separate lower-case dotted
-name. A bare path takes the label derived from its attribute, so "costCenter"
-becomes "cost_center", and two entries claiming one label refuse the boot. The
-platform stores the label as group metadata. Consumers read it over the identity
-RPCs and decide for themselves what to do with it. Two things to know before
-turning it on. There is no cardinality cap, so nominating a per-user attribute
-such as userName mints one group per user. And removing a variable does not
-delete its groups immediately: they drain on the next cycle and are deleted 90
-days later, which is the window to notice a typo before every budget and grant
-attached to them is lost.
+"cost_center" # label its UserGroups carry - id: "entra-prod" issuer_url:
+"https://login.microsoftonline.com/<tenant-id>/v2.0" audience:
+"enterprise-manager" binding_claim: "oid" # Entra's immutable user object ID
+provisioning_attribute: "externalId" # ONLY after remapping externalId to
+objectId in Entra (below) scim_bearer_token_ref: namespace: "stacklok" name:
+"directory-scim-token-entra" key: "token" Microsoft Entra ID needs an Entra-side
+change. binding_claim and provisioning_attribute must name the same identifier,
+and Entra's default SCIM attribute mapping sources externalId from mailNickname,
+not from the objectId the oid claim carries. Left as is, an issuer with
+binding_claim "oid" refuses every user Entra provisions (400 invalidValue) and
+stores none of them. In the Entra enterprise application, under Provisioning
+> Attribute mappings > Provision Microsoft Entra ID Users, map objectId
+to externalId, then set provisioning_attribute explicitly to confirm it. An
+Entra v2.0 issuer (issuer_url on login.microsoftonline.com,
+login.microsoftonline.us or login.partner.microsoftonline.cn) that leaves
+provisioning_attribute unset boots with a WARN naming this. See the Microsoft
+Entra ID section of docs/customer/install-helm.md. group_variables is the only
+surface that enables generated UserGroups: one group per distinct value the
+attribute carries on this issuer's active users, compared with surrounding
+whitespace trimmed and letter case folded, so "Marketing" and "marketing" are
+one group whose membership is the union of both. Membership is kept in step with
+the user table hourly. There is no Admin equivalent — an Admin governs the
+resulting groups but cannot cause them to exist. Paths are written in SCIM
+attribute path notation, so an extension attribute carries its full URN, and a
+malformed one refuses the boot. `label` is the ONE place a label is authored: a
+SCIM path carries schema URNs and camel case, so the label is a separate
+lower-case dotted name. A bare path takes the label derived from its attribute,
+so "costCenter" becomes "cost_center", and two entries claiming one label refuse
+the boot. The platform stores the label as group metadata. Consumers read it
+over the identity RPCs and decide for themselves what to do with it. Two things
+to know before turning it on. There is no cardinality cap, so nominating a
+per-user attribute such as userName mints one group per user. And removing a
+variable does not delete its groups immediately: they drain on the next cycle
+and are deleted 90 days later, which is the window to notice a typo before every
+budget and grant attached to them is lost.
### `directory.oktaReconcilers`
diff --git a/docs/platform/reference/helm/platform.mdx b/docs/platform/reference/helm/platform.mdx
index dedcff46..b5fd7d75 100644
--- a/docs/platform/reference/helm/platform.mdx
+++ b/docs/platform/reference/helm/platform.mdx
@@ -11,8 +11,8 @@ Configure the platform chart with these Helm values.
This reference lists values declared in the chart's default `values.yaml`.
Templates can also accept optional settings and inherited `global` values.
-Chart: `stacklok-enterprise-platform`. Chart version: `0.22.0`. Generated from
-the platform source at `e71926418e98c7598815d0abf07039d3c1646f21`.
+Chart: `stacklok-enterprise-platform`. Chart version: `0.23.0`. Generated from
+the platform source at `v0.23.0`.
## Values
@@ -151,6 +151,23 @@ PostgreSQL URI for the optional preflight database probe. Supply it only for a
one-off preflight run: a persistent values file stores its password in the
rendered preflight Secret. Empty disables the probe.
+### `enterprise-manager.serviceAccount`
+
+**Type:** `object`
+
+**Default:** `{"automount":true,"create":true}`
+
+enterprise-manager runs as a ServiceAccount of its own rather than the
+namespace's `default` one. connector-gateway admits exactly this subject to its
+internal API (internalApi.allowedSubjects), which can revoke any user's stored
+upstream tokens; deriving `default` there would admit every pod in the namespace
+that runs as it. The chart's RBAC bindings follow serviceAccountName, and
+automount keeps the in-cluster API access the `default` SA gave it (Directory,
+leader election). The ServiceAccount is named after the release
+(<release>-enterprise-manager, or the release name when it already
+contains "enterprise-manager"); renaming it requires setting
+connector-gateway.internalApi.allowedSubjects to match.
+
### `enterprise-manager.grpc.insecure`
**Type:** `bool`
@@ -504,6 +521,23 @@ Fallback installation toggle when global.stacklok.connectorGateway.enabled is
absent. The explicit false default keeps the gateway disabled when
global.stacklok is null.
+### `connector-gateway.internalApi`
+
+**Type:** `object`
+
+**Default:** `{"deriveEnterpriseManagerSubject":true,"enabled":true}`
+
+The internal API is on whenever the gateway is installed: deleting a Connection
+calls it to revoke the user's orphaned upstream token, and Connector tool
+refresh calls it too. With internalApi.allowedSubjects empty the gateway chart
+admits enterprise-manager's own ServiceAccount (see
+enterprise-manager.serviceAccount above), and enterprise-manager derives the
+internal Service's address. connector-gateway-internal-api-guard.yaml refuses
+the render when a rename, a moved port, a disabled internal API or a mismatched
+audience would leave the two sides disagreeing. With networkPolicy.enabled and
+allowExternalEgress false, the gateway also needs egress to the kube-apiserver
+for the ServiceAccount signing keys, or every Disconnect answers 502.
+
### `ai-gateway-v2.enabled`
**Type:** `bool`
@@ -737,6 +771,15 @@ Allow a clientClaim outside the supported list. Configure only when the IdP's
claim reliably identifies the requesting client; a claim shared across clients
can defeat client validation.
+### `global.stacklok.primaryIdp.subjectClaim`
+
+**Type:** `string`
+
+**Default:** `""`
+
+Token claim Connector Gateway's primary-IdP upstream resolves user subjects on.
+Empty uses sub; Microsoft Entra ID needs oid.
+
### `global.stacklok.primaryIdp.allowPrivateIps`
**Type:** `bool`
diff --git a/docs/platform/reference/helm/registry-server.mdx b/docs/platform/reference/helm/registry-server.mdx
index aa8efd38..9e8aff6c 100644
--- a/docs/platform/reference/helm/registry-server.mdx
+++ b/docs/platform/reference/helm/registry-server.mdx
@@ -12,8 +12,8 @@ Configure the Registry Server chart with these Helm values.
This reference lists values declared in the chart's default `values.yaml`.
Templates can also accept optional settings and inherited `global` values.
-Chart: `toolhive-registry-server`. Chart version: `0.22.0`. Generated from the
-platform source at `e71926418e98c7598815d0abf07039d3c1646f21`.
+Chart: `toolhive-registry-server`. Chart version: `0.23.0`. Generated from the
+platform source at `v0.23.0`.
## Values
@@ -91,7 +91,7 @@ deployment and Service the name registry-api.
Default value
```yaml
-image-proxy.stacklok.com/proxy/stacklok-enterprise/ghcr.io/stacklok/stacklok-enterprise/registry-api:0.22.0
+image-proxy.stacklok.com/proxy/stacklok-enterprise/ghcr.io/stacklok/stacklok-enterprise/registry-api:0.23.0
```
diff --git a/docs/platform/reference/helm/toolhive-operator-crds.mdx b/docs/platform/reference/helm/toolhive-operator-crds.mdx
index 157e21b6..0c66cbf1 100644
--- a/docs/platform/reference/helm/toolhive-operator-crds.mdx
+++ b/docs/platform/reference/helm/toolhive-operator-crds.mdx
@@ -12,8 +12,8 @@ Configure the ToolHive operator CRD chart with these Helm values.
This reference lists values declared in the chart's default `values.yaml`.
Templates can also accept optional settings and inherited `global` values.
-Chart: `toolhive-operator-crds`. Chart version: `0.22.0`. Generated from the
-platform source at `e71926418e98c7598815d0abf07039d3c1646f21`.
+Chart: `toolhive-operator-crds`. Chart version: `0.23.0`. Generated from the
+platform source at `v0.23.0`.
## Values
diff --git a/docs/platform/reference/helm/toolhive-operator.mdx b/docs/platform/reference/helm/toolhive-operator.mdx
index 3b84ab1a..406ed38e 100644
--- a/docs/platform/reference/helm/toolhive-operator.mdx
+++ b/docs/platform/reference/helm/toolhive-operator.mdx
@@ -12,8 +12,8 @@ Configure the ToolHive operator chart with these Helm values.
This reference lists values declared in the chart's default `values.yaml`.
Templates can also accept optional settings and inherited `global` values.
-Chart: `toolhive-operator`. Chart version: `0.22.0`. Generated from the platform
-source at `e71926418e98c7598815d0abf07039d3c1646f21`.
+Chart: `toolhive-operator`. Chart version: `0.23.0`. Generated from the platform
+source at `v0.23.0`.
## Values
@@ -82,7 +82,7 @@ part-of keeps it off the registry-server pods, which share the same alias name.
Default value
```yaml
-image-proxy.stacklok.com/proxy/stacklok-enterprise/ghcr.io/stacklok/stacklok-enterprise/operator:0.22.0
+image-proxy.stacklok.com/proxy/stacklok-enterprise/ghcr.io/stacklok/stacklok-enterprise/operator:0.23.0
```
@@ -97,7 +97,7 @@ Container image for the Stacklok Enterprise ToolHive operator.
Default value
```yaml
-image-proxy.stacklok.com/proxy/stacklok-enterprise/ghcr.io/stacklok/stacklok-enterprise/proxyrunner:0.22.0
+image-proxy.stacklok.com/proxy/stacklok-enterprise/ghcr.io/stacklok/stacklok-enterprise/proxyrunner:0.23.0
```
@@ -112,7 +112,7 @@ Default proxy runner image injected into MCPServer workloads by the operator.
Default value
```yaml
-image-proxy.stacklok.com/proxy/stacklok-enterprise/ghcr.io/stacklok/stacklok-enterprise/vmcp:0.22.0
+image-proxy.stacklok.com/proxy/stacklok-enterprise/ghcr.io/stacklok/stacklok-enterprise/vmcp:0.23.0
```
@@ -164,7 +164,7 @@ update check because enterprise releases follow their own schedule.
Default value
```yaml
-image-proxy.stacklok.com/proxy/stacklok-enterprise/ghcr.io/stacklok/stacklok-enterprise/registry-api:0.22.0
+image-proxy.stacklok.com/proxy/stacklok-enterprise/ghcr.io/stacklok/stacklok-enterprise/registry-api:0.23.0
```
diff --git a/static/api-specs/connector-gateway-api.json b/static/api-specs/connector-gateway-api.json
index 9ee751c5..265e809b 100644
--- a/static/api-specs/connector-gateway-api.json
+++ b/static/api-specs/connector-gateway-api.json
@@ -15,7 +15,8 @@
"enum": [
"ready",
"needs_auth",
- "connected"
+ "connected",
+ "not_served"
],
"type": "string"
},
@@ -43,7 +44,8 @@
"enum": [
"ready",
"needs_auth",
- "connected"
+ "connected",
+ "not_served"
],
"type": "string"
}
@@ -129,6 +131,66 @@
}
},
"type": "object"
+ },
+ "internal_app.ServedTool": {
+ "properties": {
+ "annotations": {
+ "$ref": "#/components/schemas/internal_app.ToolCatalogueAnnotations"
+ },
+ "connector_id": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "input_schema": {
+ "additionalProperties": {},
+ "type": "object"
+ },
+ "native_name": {
+ "type": "string"
+ },
+ "output_schema": {
+ "additionalProperties": {},
+ "type": "object"
+ },
+ "served_name": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "internal_app.ToolCatalogueAnnotations": {
+ "properties": {
+ "destructiveHint": {
+ "type": "boolean"
+ },
+ "idempotentHint": {
+ "type": "boolean"
+ },
+ "openWorldHint": {
+ "type": "boolean"
+ },
+ "readOnlyHint": {
+ "type": "boolean"
+ },
+ "title": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "internal_app.ToolCatalogueResponse": {
+ "properties": {
+ "tools": {
+ "items": {
+ "$ref": "#/components/schemas/internal_app.ServedTool"
+ },
+ "type": "array",
+ "uniqueItems": false
+ }
+ },
+ "type": "object"
}
},
"securitySchemes": {
@@ -409,6 +471,17 @@
"schema": {
"type": "string"
}
+ },
+ {
+ "description": "Set to setup for an admin's tool sync; omit for ordinary use",
+ "in": "query",
+ "name": "purpose",
+ "schema": {
+ "enum": [
+ "setup"
+ ],
+ "type": "string"
+ }
}
],
"responses": {
@@ -452,6 +525,26 @@
},
"description": "Not Found"
},
+ "409": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ },
+ "description": "Conflict"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ },
"502": {
"content": {
"application/json": {
@@ -465,6 +558,45 @@
},
"summary": "List a Connector's Tools"
}
+ },
+ "/v1/users/me/gateway/tool-catalogue": {
+ "get": {
+ "description": "Returns native and served names from live gateway routing. This discovery projection is not an execution credential.",
+ "operationId": "getMyServedToolCatalogue",
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/internal_app.ToolCatalogueResponse"
+ }
+ }
+ },
+ "description": "OK"
+ },
+ "401": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ },
+ "description": "Unauthorized"
+ },
+ "503": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ErrorResponse"
+ }
+ }
+ },
+ "description": "Service Unavailable"
+ }
+ },
+ "summary": "Get the caller's served tool catalogue"
+ }
}
},
"openapi": "3.1.0",
diff --git a/static/api-specs/enterprise-manager-api.json b/static/api-specs/enterprise-manager-api.json
index 4bafe31f..786ff0d5 100644
--- a/static/api-specs/enterprise-manager-api.json
+++ b/static/api-specs/enterprise-manager-api.json
@@ -3,6 +3,13 @@
"schemas": {
"github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_budgets_v1.BreakdownEntry": {
"properties": {
+ "principal_kind": {
+ "enum": [
+ "user",
+ "service_account"
+ ],
+ "type": "string"
+ },
"used_usd": {
"type": "string"
},
@@ -67,11 +74,11 @@
"type": "string"
},
"scope": {
- "description": "Scope is the principal tier: \"user\" or \"group\".",
+ "description": "Scope is the principal tier: \"user\", \"group\", or \"service_account\".",
"type": "string"
},
"subject_id": {
- "description": "SubjectID is the opaque principal identifier: the directory platform user\nUUID for a user budget, the directory group UUID for a group budget.",
+ "description": "SubjectID is the opaque principal identifier: the directory platform user\nUUID for a user budget, the directory group UUID for a group budget, or\nthe directory service account UUID.",
"type": "string"
}
},
@@ -232,8 +239,15 @@
"type": "array",
"uniqueItems": false
},
- "platform_user_id": {
- "description": "Typed identity; empty until the directory service is wired.",
+ "principal_id": {
+ "description": "Resolved caller's UUID and kind; both absent when unresolved.",
+ "type": "string"
+ },
+ "principal_kind": {
+ "enum": [
+ "user",
+ "service_account"
+ ],
"type": "string"
},
"provider": {
@@ -478,6 +492,13 @@
},
"outputUsdPerMillion": {
"type": "string"
+ },
+ "promptSizeTiers": {
+ "items": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_budgets_v1.PricingPromptSizeTier"
+ },
+ "type": "array",
+ "uniqueItems": false
}
},
"type": "object"
@@ -512,7 +533,7 @@
"type": "string"
},
"unpriced": {
- "description": "Unpriced marks a tombstone: a rate an admin deliberately removed,\nrecorded rather than left as an absence, so no refresh resurrects it. A\ntombstone carries no rate block, and the entry is skipped when the\nCostCatalog is built, so the model is unpriceable and denied at admission\n(toolhive-enterprise ADR-0021) unless another spelling folds onto the\nsame canonical key and prices it.",
+ "description": "Unpriced marks a tombstone: a rate an admin deliberately removed,\nrecorded rather than left as an absence, so no refresh resurrects it. A\ntombstone carries no rate block, and the entry is skipped when the\nCostCatalog is built, so the model is unpriceable and denied at admission\n(enterprise/toolhive-enterprise/docs/design/budgets-admission.md) unless another spelling folds onto the\nsame canonical key and prices it.",
"type": "boolean"
}
},
@@ -625,6 +646,12 @@
"aboveTokens": {
"type": "integer"
},
+ "cacheCreation1hInputUsdPerMillion": {
+ "type": "string"
+ },
+ "cacheCreation5mInputUsdPerMillion": {
+ "type": "string"
+ },
"cachedInputUsdPerMillion": {
"type": "string"
},
@@ -716,6 +743,17 @@
},
"type": "object"
},
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_budgets_v1.PutServiceAccountBudgetRequest": {
+ "properties": {
+ "limit_usd": {
+ "type": "string"
+ },
+ "period": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
"github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_budgets_v1.PutUserBudgetRequest": {
"properties": {
"limit_usd": {
@@ -790,12 +828,38 @@
},
"type": "object"
},
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorDetail": {
+ "properties": {
+ "code": {
+ "description": "Code is the specific machine-readable reason within Type. Optional: a\nmessage-only error omits it.",
+ "example": "administratively_disconnected",
+ "type": "string"
+ },
+ "message": {
+ "description": "Message is the human-readable description, safe to show to the caller.",
+ "example": "connector not found",
+ "type": "string"
+ },
+ "type": {
+ "description": "Type is the broad class of the error. Optional: a message-only error\nomits it.",
+ "example": "gateway_disconnected",
+ "type": "string"
+ }
+ },
+ "required": [
+ "message"
+ ],
+ "type": "object"
+ },
"github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse": {
"properties": {
"error": {
- "type": "string"
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorDetail"
}
},
+ "required": [
+ "error"
+ ],
"type": "object"
},
"github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.AWSStsAuthDTO": {
@@ -868,6 +932,14 @@
],
"type": "object"
},
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.BearerTokenAuthDTO": {
+ "properties": {
+ "token": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ClientSecretRefDTO"
+ }
+ },
+ "type": "object"
+ },
"github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.BearerTokenAuthRequest": {
"properties": {
"token": {
@@ -876,6 +948,53 @@
},
"type": "object"
},
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.BulkToggleGroupToolRequest": {
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ },
+ "group_ids": {
+ "items": {
+ "type": "string"
+ },
+ "maxItems": 200,
+ "minItems": 1,
+ "type": "array",
+ "uniqueItems": false
+ },
+ "tool_id": {
+ "maxLength": 256,
+ "type": "string"
+ }
+ },
+ "required": [
+ "enabled",
+ "group_ids",
+ "tool_id"
+ ],
+ "type": "object"
+ },
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.BulkToggleGroupToolResponse": {
+ "properties": {
+ "connector_id": {
+ "type": "string"
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "results": {
+ "items": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.GroupToolToggleResultDTO"
+ },
+ "type": "array",
+ "uniqueItems": false
+ },
+ "tool_id": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
"github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ClientSecretRefDTO": {
"properties": {
"kubernetes_secret": {
@@ -904,6 +1023,10 @@
"id": {
"type": "string"
},
+ "setup_access_until": {
+ "description": "SetupAccessUntil is when the owner's setup access to the Connector lapses. Absent when\nthe Connection carries none.",
+ "type": "string"
+ },
"tools_enabled_by_default": {
"type": "boolean"
},
@@ -928,6 +1051,9 @@
"aws_sts": {
"$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.AWSStsAuthDTO"
},
+ "bearer_token": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.BearerTokenAuthDTO"
+ },
"header_injection": {
"$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.HeaderInjectionAuthDTO"
},
@@ -1139,6 +1265,41 @@
},
"type": "object"
},
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ConnectorToolDTO": {
+ "properties": {
+ "description": {
+ "type": "string"
+ },
+ "destructive_hint": {
+ "type": "boolean"
+ },
+ "name": {
+ "type": "string"
+ },
+ "read_only_hint": {
+ "type": "boolean"
+ }
+ },
+ "type": "object"
+ },
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ConnectorToolsDTO": {
+ "properties": {
+ "connector_id": {
+ "type": "string"
+ },
+ "last_refreshed_at": {
+ "type": "string"
+ },
+ "tools": {
+ "items": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ConnectorToolDTO"
+ },
+ "type": "array",
+ "uniqueItems": false
+ }
+ },
+ "type": "object"
+ },
"github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ConnectorWriteRequest": {
"properties": {
"allow_private_ips": {
@@ -1254,6 +1415,31 @@
],
"type": "object"
},
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.CreateExternalBindingRequest": {
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "namespace": {
+ "type": "string"
+ },
+ "reassign": {
+ "type": "boolean"
+ },
+ "uid": {
+ "type": "string"
+ },
+ "workload_trust_id": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "name",
+ "namespace",
+ "workload_trust_id"
+ ],
+ "type": "object"
+ },
"github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.CreateGroupRequest": {
"properties": {
"description": {
@@ -1337,6 +1523,66 @@
],
"type": "object"
},
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.CreateServiceAccountRequest": {
+ "properties": {
+ "description": {
+ "type": "string"
+ },
+ "display_name": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "display_name"
+ ],
+ "type": "object"
+ },
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.CreateWorkloadTrustRequest": {
+ "properties": {
+ "allowed_algorithms": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "uniqueItems": false
+ },
+ "audiences": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "uniqueItems": false
+ },
+ "issuer": {
+ "type": "string"
+ },
+ "key_source": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.WorkloadTrustKeySourceDTO"
+ },
+ "profile": {
+ "enum": [
+ "kubernetes_projected_token"
+ ],
+ "type": "string"
+ },
+ "status": {
+ "enum": [
+ "enabled",
+ "disabled"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "allowed_algorithms",
+ "audiences",
+ "issuer",
+ "key_source",
+ "profile",
+ "status"
+ ],
+ "type": "object"
+ },
"github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.DCRConfigDTO": {
"properties": {
"discovery_url": {
@@ -1376,6 +1622,9 @@
"authorization_server": {
"type": "string"
},
+ "dcr_supported": {
+ "type": "boolean"
+ },
"discovery_url": {
"type": "string"
},
@@ -1412,9 +1661,9 @@
"required": [
"authorization_endpoint",
"authorization_server",
+ "dcr_supported",
"discovery_url",
"mcp_url",
- "registration_endpoint",
"resource",
"resource_metadata_url",
"token_endpoint"
@@ -1485,6 +1734,32 @@
},
"type": "object"
},
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ExternalBindingDTO": {
+ "properties": {
+ "created_at": {
+ "type": "string"
+ },
+ "id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ },
+ "namespace": {
+ "type": "string"
+ },
+ "service_account_id": {
+ "type": "string"
+ },
+ "uid": {
+ "type": "string"
+ },
+ "workload_trust_id": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
"github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.GrantConnectorPolicyUserGroupsRequest": {
"properties": {
"group_ids": {
@@ -1504,18 +1779,19 @@
"github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.GrantSourceDTO": {
"properties": {
"group_id": {
- "description": "GroupID and GroupName are ABSENT for \"default\" and \"user\" sources, which\ncarry no group. They are an omitempty pointer rather than an empty string\nso a client cannot render the zero UUID as if it named a group, and so the\nwire matches the generated `group_id?: string` instead of sending null.",
+ "description": "GroupID and GroupName are ABSENT for every source but \"group\", which alone\ncarries a group. They are an omitempty pointer rather than an empty string\nso a client cannot render the zero UUID as if it named a group, and so the\nwire matches the generated `group_id?: string` instead of sending null.",
"type": "string"
},
"group_name": {
"type": "string"
},
"kind": {
- "description": "Kind is \"default\", \"user\", or \"group\" — the same spelling GrantSubjectDTO\nuses, so a client reads one vocabulary across both endpoints.",
+ "description": "Kind uses GrantSubjectDTO's spelling, so a client reads one vocabulary\nacross both endpoints.",
"enum": [
"default",
"user",
- "group"
+ "group",
+ "service_account"
],
"type": "string"
}
@@ -1538,15 +1814,15 @@
"type": "string"
},
"kind": {
- "description": "Kind is \"user\" or \"group\".",
"enum": [
"user",
- "group"
+ "group",
+ "service_account"
],
"type": "string"
},
"source": {
- "description": "Source is a group's provenance, as stored; absent for a user. Clients own\nany display mapping of the raw value.",
+ "description": "Source is a group's provenance, as stored; absent for any other kind.\nClients own any display mapping of the raw value.",
"enum": [
"scim",
"api",
@@ -1646,10 +1922,42 @@
},
"type": "object"
},
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.GroupToolToggleResultDTO": {
+ "properties": {
+ "group_id": {
+ "type": "string"
+ },
+ "message": {
+ "type": "string"
+ },
+ "reason": {
+ "enum": [
+ "invalid_group_id",
+ "group_not_found",
+ "no_tool_restriction",
+ "conflict",
+ "internal_error"
+ ],
+ "type": "string"
+ },
+ "status": {
+ "enum": [
+ "updated",
+ "unchanged",
+ "failed"
+ ],
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
"github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.HeaderInjectionAuthDTO": {
"properties": {
"header_name": {
"type": "string"
+ },
+ "value": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ClientSecretRefDTO"
}
},
"type": "object"
@@ -1802,15 +2110,28 @@
"next_groups_cursor": {
"type": "string"
},
+ "next_service_accounts_cursor": {
+ "type": "string"
+ },
"next_users_cursor": {
"type": "string"
},
"prev_groups_cursor": {
"type": "string"
},
+ "prev_service_accounts_cursor": {
+ "type": "string"
+ },
"prev_users_cursor": {
"type": "string"
},
+ "service_accounts": {
+ "items": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ServiceAccountDTO"
+ },
+ "type": "array",
+ "uniqueItems": false
+ },
"transitive_users": {
"items": {
"$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.UserDTO"
@@ -1934,6 +2255,9 @@
"description": "PrevCursor is present only when an earlier page exists; pass it as before.",
"type": "string"
},
+ "service_account_grants": {
+ "type": "integer"
+ },
"subjects": {
"description": "Subjects is one page of the grant holders, ordered by kind then\ncase-insensitive name. The counts above are totals on every page,\nwhatever the kind filter or cursor.",
"items": {
@@ -2050,12 +2374,15 @@
"type": "string"
},
"cache_skew": {
- "description": "CacheSkew renders the domain's *time.Duration as its Go duration string\n(e.g. \"5m\"), or is absent when unset — the OBO cache applies its own skew\nat dial time, so absence is meaningful (ADR-0024).",
+ "description": "CacheSkew renders the domain's *time.Duration as its Go duration string\n(e.g. \"5m\"), or is absent when unset — the OBO cache applies its own skew\nat dial time, so absence is meaningful.",
"type": "string"
},
"client_id": {
"type": "string"
},
+ "client_secret": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ClientSecretRefDTO"
+ },
"provider_id": {
"type": "string"
},
@@ -2208,17 +2535,98 @@
],
"type": "object"
},
- "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.RoleMappingDTO": {
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ReplaceServiceAccountRequest": {
"properties": {
- "claim": {
+ "created_by": {
"type": "string"
},
- "matcher": {
+ "description": {
"type": "string"
},
- "priority": {
- "type": "integer"
- },
+ "display_name": {
+ "type": "string"
+ },
+ "id": {
+ "type": "string"
+ },
+ "status": {
+ "enum": [
+ "suspended",
+ "active",
+ "deprovisioned"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "display_name",
+ "status"
+ ],
+ "type": "object"
+ },
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ReplaceWorkloadTrustRequest": {
+ "properties": {
+ "allowed_algorithms": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "uniqueItems": false
+ },
+ "audiences": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "uniqueItems": false
+ },
+ "id": {
+ "type": "string"
+ },
+ "issuer": {
+ "type": "string"
+ },
+ "key_source": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.WorkloadTrustKeySourceDTO"
+ },
+ "profile": {
+ "enum": [
+ "kubernetes_projected_token"
+ ],
+ "type": "string"
+ },
+ "revision": {
+ "type": "integer"
+ },
+ "status": {
+ "enum": [
+ "enabled",
+ "disabled"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "allowed_algorithms",
+ "audiences",
+ "issuer",
+ "key_source",
+ "profile",
+ "status"
+ ],
+ "type": "object"
+ },
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.RoleMappingDTO": {
+ "properties": {
+ "claim": {
+ "type": "string"
+ },
+ "matcher": {
+ "type": "string"
+ },
+ "priority": {
+ "type": "integer"
+ },
"role_arn": {
"type": "string"
}
@@ -2242,6 +2650,37 @@
},
"type": "object"
},
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ServiceAccountDTO": {
+ "properties": {
+ "created_at": {
+ "type": "string"
+ },
+ "created_by": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "display_name": {
+ "type": "string"
+ },
+ "id": {
+ "type": "string"
+ },
+ "status": {
+ "enum": [
+ "suspended",
+ "active",
+ "deprovisioned"
+ ],
+ "type": "string"
+ },
+ "updated_at": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
"github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.SetConnectionEnabledRequest": {
"properties": {
"enabled": {
@@ -2312,8 +2751,8 @@
"client_id": {
"type": "string"
},
- "client_secret_configured": {
- "type": "boolean"
+ "client_secret": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ClientSecretRefDTO"
},
"external_token_header_name": {
"type": "string"
@@ -2432,11 +2871,86 @@
},
"type": "object"
},
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.WorkloadTrustDTO": {
+ "properties": {
+ "allowed_algorithms": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "uniqueItems": false
+ },
+ "audiences": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array",
+ "uniqueItems": false
+ },
+ "created_at": {
+ "type": "string"
+ },
+ "id": {
+ "type": "string"
+ },
+ "issuer": {
+ "type": "string"
+ },
+ "key_source": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.WorkloadTrustKeySourceDTO"
+ },
+ "profile": {
+ "enum": [
+ "kubernetes_projected_token"
+ ],
+ "type": "string"
+ },
+ "revision": {
+ "type": "integer"
+ },
+ "status": {
+ "enum": [
+ "enabled",
+ "disabled"
+ ],
+ "type": "string"
+ },
+ "updated_at": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.WorkloadTrustKeySourceDTO": {
+ "properties": {
+ "jwks_document": {
+ "type": "string"
+ },
+ "jwks_url": {
+ "type": "string"
+ },
+ "type": {
+ "enum": [
+ "jwks_url",
+ "jwks_document",
+ "in_cluster"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "type": "object"
+ },
"github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.XAAAuthDTO": {
"properties": {
"idp_client_id": {
"type": "string"
},
+ "idp_client_secret": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ClientSecretRefDTO"
+ },
"idp_token_url": {
"type": "string"
},
@@ -2462,6 +2976,9 @@
"target_client_id": {
"type": "string"
},
+ "target_client_secret": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ClientSecretRefDTO"
+ },
"target_resource": {
"type": "string"
},
@@ -2753,7 +3270,7 @@
"type": "string"
},
"user_email": {
- "description": "UserEmail is the display email resolved from UserID (ADR-0025),\nempty when unresolved (no resolver wired, or an authoritative miss)\n— the caller renders UserID's raw UUID in that case. Distinct from\nUserID: this is a read-time enrichment, never a stored field.",
+ "description": "UserEmail is the display email resolved from UserID\n(enterprise/toolhive-enterprise/docs/design/metering.md),\nempty when unresolved (no resolver wired, or an authoritative miss)\n— the caller renders UserID's raw UUID in that case. Distinct from\nUserID: this is a read-time enrichment, never a stored field.",
"type": "string"
},
"user_id": {
@@ -3321,6 +3838,24 @@
},
"type": "object"
},
+ "internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_ExternalBindingDTO": {
+ "properties": {
+ "items": {
+ "items": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ExternalBindingDTO"
+ },
+ "type": "array",
+ "uniqueItems": false
+ },
+ "next_cursor": {
+ "type": "string"
+ },
+ "prev_cursor": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
"internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_GroupDTO": {
"properties": {
"items": {
@@ -3393,6 +3928,24 @@
},
"type": "object"
},
+ "internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_ServiceAccountDTO": {
+ "properties": {
+ "items": {
+ "items": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ServiceAccountDTO"
+ },
+ "type": "array",
+ "uniqueItems": false
+ },
+ "next_cursor": {
+ "type": "string"
+ },
+ "prev_cursor": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
"internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_UserDTO": {
"properties": {
"items": {
@@ -3410,6 +3963,24 @@
}
},
"type": "object"
+ },
+ "internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_WorkloadTrustDTO": {
+ "properties": {
+ "items": {
+ "items": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.WorkloadTrustDTO"
+ },
+ "type": "array",
+ "uniqueItems": false
+ },
+ "next_cursor": {
+ "type": "string"
+ },
+ "prev_cursor": {
+ "type": "string"
+ }
+ },
+ "type": "object"
}
},
"securitySchemes": {
@@ -3971,13 +4542,14 @@
"schema": {
"enum": [
"user",
- "group"
+ "group",
+ "service_account"
],
"type": "string"
}
},
{
- "description": "Budget subject id (directory platform user UUID for user budgets, directory group UUID for group budgets)",
+ "description": "Budget subject id (directory platform user UUID for user budgets, directory group UUID for group budgets, directory service account UUID for service-account budgets)",
"in": "query",
"name": "subject_id",
"required": true,
@@ -4073,7 +4645,8 @@
"schema": {
"enum": [
"user",
- "group"
+ "group",
+ "service_account"
],
"type": "string"
}
@@ -5229,53 +5802,293 @@
]
}
},
- "/v1/budgets/spend": {
- "get": {
- "description": "Zero-filled daily USD totals over the served window, including the current (in-progress) UTC day. from/to echo the bounds actually served after clamping (to at the end of the current UTC day, from at the retention horizon).",
+ "/v1/budgets/service-accounts/{id}": {
+ "delete": {
"parameters": [
{
- "description": "Bucket granularity",
- "in": "query",
- "name": "granularity",
- "schema": {
- "enum": [
- "day"
- ],
- "type": "string"
- }
- },
- {
- "description": "Window start, ISO date (default 30 days back, including today)",
- "in": "query",
- "name": "from",
+ "description": "ETag from GET /v1/budgets",
+ "in": "header",
+ "name": "If-Match",
"schema": {
"type": "string"
}
},
{
- "description": "Window end (exclusive), ISO date",
- "in": "query",
- "name": "to",
+ "description": "Directory service account UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
"schema": {
"type": "string"
}
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "Service account budget removed"
},
- {
- "description": "Served model of the underlying event, exact match",
- "in": "query",
- "name": "model",
- "schema": {
- "type": "string"
- }
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
},
- {
- "description": "Payer tier charged",
- "in": "query",
- "name": "scope",
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "412": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Precondition Failed"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Delete service account budget",
+ "tags": [
+ "budgets"
+ ]
+ },
+ "get": {
+ "description": "A service account's current-period spend on its own allowance, sliced by one dimension. Entries sum to total_used_usd.",
+ "parameters": [
+ {
+ "description": "Directory service account UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Slice axis",
+ "in": "query",
+ "name": "dimension",
+ "required": true,
+ "schema": {
+ "enum": [
+ "model"
+ ],
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_budgets_v1.DimensionSliceResponse"
+ }
+ }
+ },
+ "description": "OK"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Service account budget breakdown slice",
+ "tags": [
+ "budgets"
+ ]
+ },
+ "put": {
+ "parameters": [
+ {
+ "description": "ETag from GET /v1/budgets",
+ "in": "header",
+ "name": "If-Match",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Directory service account UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ {
+ "type": "object"
+ },
+ {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_budgets_v1.PutServiceAccountBudgetRequest",
+ "summary": "body",
+ "description": "Service account budget specification"
+ }
+ ]
+ }
+ }
+ },
+ "description": "Service account budget specification",
+ "required": true
+ },
+ "responses": {
+ "204": {
+ "description": "Service account budget applied"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "412": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Precondition Failed"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Put service account budget",
+ "tags": [
+ "budgets"
+ ]
+ }
+ },
+ "/v1/budgets/spend": {
+ "get": {
+ "description": "Zero-filled daily USD totals over the served window, including the current (in-progress) UTC day. from/to echo the bounds actually served after clamping (to at the end of the current UTC day, from at the retention horizon).",
+ "parameters": [
+ {
+ "description": "Bucket granularity",
+ "in": "query",
+ "name": "granularity",
+ "schema": {
+ "enum": [
+ "day"
+ ],
+ "type": "string"
+ }
+ },
+ {
+ "description": "Window start, ISO date (default 30 days back, including today)",
+ "in": "query",
+ "name": "from",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Window end (exclusive), ISO date",
+ "in": "query",
+ "name": "to",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Served model of the underlying event, exact match",
+ "in": "query",
+ "name": "model",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Payer tier charged",
+ "in": "query",
+ "name": "scope",
"schema": {
"enum": [
"user",
- "group"
+ "group",
+ "service_account"
],
"type": "string"
}
@@ -5334,10 +6147,10 @@
},
"/v1/budgets/spend/export": {
"get": {
- "description": "A grouped, bucketed rollup of charge records as CSV, sorted bucket ascending then charged_usd descending then group key(s) ascending. A single group_by dimension renders a fixed \"group_key\" column; two or more render one named column per dimension, in the order given. The served window (after default/retention clamping) is echoed in the X-Spend-Export-From/To response headers. Experiment-gated; 404s when the operator has not enabled it.",
+ "description": "A grouped, bucketed rollup of charge records as CSV, sorted bucket ascending then charged_usd descending then group key(s) ascending. A single model or provider dimension renders a fixed \"group_key\" column; any other grouping renders one named column per dimension, in the order given. The principal dimension renders three adjacent columns, principal_id (the caller's UUID, empty when unresolved), principal_kind (user or service_account) and auth_subject, and groups on all three. The served window (after default/retention clamping) is echoed in the X-Spend-Export-From/To response headers. Experiment-gated; 404s when the operator has not enabled it.",
"parameters": [
{
- "description": "Comma-separated grouping dimensions, e.g. user,model. Each must be one of user, model, provider, with no repeats. Defaults to user.",
+ "description": "Comma-separated grouping dimensions, e.g. principal,model. Each must be one of principal, model, provider, with no repeats. Defaults to principal. user is deprecated in favour of principal and renders identically.",
"in": "query",
"name": "group_by",
"schema": {
@@ -5388,7 +6201,8 @@
"schema": {
"enum": [
"user",
- "group"
+ "group",
+ "service_account"
],
"type": "string"
}
@@ -5411,7 +6225,7 @@
}
}
},
- "description": "CSV: bucket,group_key,charge_count,charged_usd for one group_by dimension; bucket,`\u003cdim1\u003e`,`\u003cdim2\u003e`,...,charge_count,charged_usd for two or more"
+ "description": "CSV: bucket,group_key,charge_count,charged_usd for one model or provider dimension; bucket,`\u003cdim1\u003e`,`\u003cdim2\u003e`,...,charge_count,charged_usd otherwise, with principal rendered as principal_id,principal_kind,auth_subject (bucket,principal_id,principal_kind,auth_subject,charge_count,charged_usd for principal alone)"
},
"400": {
"content": {
@@ -5447,10 +6261,10 @@
},
"/v1/budgets/spend/export/by-label": {
"get": {
- "description": "The spend export broken down by conversation label, as CSV, sorted bucket ascending then charged_usd descending then group key(s) ascending. Columns are bucket, one per group_by dimension in the order given, then facet and label, then charge_count and charged_usd. Rows do NOT partition total spend: a session carries one label per facet, so summing either measure across more than one facet multiplies it by the facet count, charge_count exactly as much as charged_usd — pass facet to narrow the export to one. Under a facet filter every row carries that facet, coverage rows included, so pivoting on it is safe. Charges with no label are still counted, under a label naming why: (no-session), (uncaptured), (unclassified) or (unset). The served window (after default/retention clamping) is echoed in the X-Spend-Export-From/To response headers. Experiment-gated; 404s when the operator has not enabled it.",
+ "description": "The spend export broken down by conversation label, as CSV, sorted bucket ascending then charged_usd descending then group key(s) ascending. Columns are bucket, one per group_by dimension in the order given (principal as three adjacent columns principal_id, principal_kind and auth_subject, grouped on all three; principal_id is the caller's UUID, empty when unresolved, and principal_kind is user or service_account), then facet and label, then charge_count and charged_usd. Rows do NOT partition total spend: a session carries one label per facet, so summing either measure across more than one facet multiplies it by the facet count, charge_count exactly as much as charged_usd — pass facet to narrow the export to one. Under a facet filter every row carries that facet, coverage rows included, so pivoting on it is safe. Charges with no label are still counted, under a label naming why: (no-session), (uncaptured), (unclassified) or (unset). The served window (after default/retention clamping) is echoed in the X-Spend-Export-From/To response headers. Experiment-gated; 404s when the operator has not enabled it.",
"parameters": [
{
- "description": "Comma-separated grouping dimensions, e.g. user,model. Each must be one of user, model, provider, with no repeats. Defaults to user. The facet and label columns are always present in addition to these",
+ "description": "Comma-separated grouping dimensions, e.g. principal,model. Each must be one of principal, model, provider, with no repeats. Defaults to principal. user is deprecated in favour of principal and renders identically. The facet and label columns are always present in addition to these",
"in": "query",
"name": "group_by",
"schema": {
@@ -5509,7 +6323,8 @@
"schema": {
"enum": [
"user",
- "group"
+ "group",
+ "service_account"
],
"type": "string"
}
@@ -5532,7 +6347,7 @@
}
}
},
- "description": "CSV: bucket,`\u003cdim1\u003e`,...,facet,label,charge_count,charged_usd"
+ "description": "CSV: bucket,`\u003cdim1\u003e`,...,facet,label,charge_count,charged_usd, with principal rendered as principal_id,principal_kind,auth_subject"
},
"400": {
"content": {
@@ -5576,7 +6391,8 @@
"schema": {
"enum": [
"user",
- "group"
+ "group",
+ "service_account"
],
"type": "string"
}
@@ -6063,7 +6879,7 @@
},
"/v1/connector-identity-providers/discover": {
"post": {
- "description": "Probes an MCP server and returns its RFC 9728 protected-resource and RFC 8414 authorization-server metadata.",
+ "description": "Probes an MCP server and returns its RFC 9728 protected-resource metadata and its authorization server's RFC 8414 or OpenID Connect Discovery metadata.\nA server without Dynamic Client Registration is a 200 with dcr_supported false and no registration_endpoint; its client must be pre-registered.\nA 422 carries error.type \"oauth_discovery\" and error.code \"not_protected\" (the server neither answered 401 nor publishes protected-resource metadata at a well-known URI) or \"no_metadata\" (it answered 401 but advertised no protected-resource metadata, by reference or at a well-known URI).",
"requestBody": {
"content": {
"application/json": {
@@ -6673,29 +7489,135 @@
]
}
},
- "/v1/connectors/{id}/policy": {
- "get": {
+ "/v1/connectors/{connector_id}/tool-restrictions/toggle": {
+ "post": {
"parameters": [
{
"description": "Connector UUID",
"in": "path",
- "name": "id",
+ "name": "connector_id",
"required": true,
"schema": {
"type": "string"
}
}
],
- "responses": {
- "200": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ConnectorPolicyDTO"
- }
- }
- },
- "description": "OK"
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ {
+ "type": "object"
+ },
+ {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.BulkToggleGroupToolRequest",
+ "summary": "body",
+ "description": "Tool, groups and desired state"
+ }
+ ]
+ }
+ }
+ },
+ "description": "Tool, groups and desired state",
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.BulkToggleGroupToolResponse"
+ }
+ }
+ },
+ "description": "OK"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "413": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Request Entity Too Large"
+ },
+ "422": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Unprocessable Entity"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Enable or disable one tool across many groups' restrictions on a connector",
+ "tags": [
+ "directory"
+ ]
+ }
+ },
+ "/v1/connectors/{id}/policy": {
+ "get": {
+ "parameters": [
+ {
+ "description": "Connector UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ConnectorPolicyDTO"
+ }
+ }
+ },
+ "description": "OK"
},
"400": {
"content": {
@@ -7255,13 +8177,13 @@
]
}
},
- "/v1/gateways/{gateway_id}/connectors": {
+ "/v1/connectors/{id}/tools": {
"get": {
"parameters": [
{
- "description": "Connector-gateway install id",
+ "description": "Connector UUID",
"in": "path",
- "name": "gateway_id",
+ "name": "id",
"required": true,
"schema": {
"type": "string"
@@ -7273,12 +8195,32 @@
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_ConnectorDTO"
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ConnectorToolsDTO"
}
}
},
"description": "OK"
},
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
"500": {
"content": {
"application/json": {
@@ -7295,53 +8237,36 @@
"BearerAuth": []
}
],
- "summary": "List connectors",
+ "summary": "Get a connector's tool list",
"tags": [
"directory"
]
- },
+ }
+ },
+ "/v1/connectors/{id}/tools/refresh": {
"post": {
+ "description": "A connector that authenticates per user is listed as the calling admin, with the request's own bearer token, through the connector-gateway. Its refusals carry a code: 403 admin_not_granted (the gateway does not serve the connector to the admin: the admin is in no group granted it, or the gateway is not serving it) and 409 admin_connect_required (the admin must connect to the connector's upstream provider first). 422 means this installation cannot list per-user connectors at all.",
"parameters": [
{
- "description": "Connector-gateway install id",
+ "description": "Connector UUID",
"in": "path",
- "name": "gateway_id",
+ "name": "id",
"required": true,
"schema": {
"type": "string"
}
}
],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "oneOf": [
- {
- "type": "object"
- },
- {
- "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ConnectorWriteRequest",
- "summary": "body",
- "description": "Connector to create"
- }
- ]
- }
- }
- },
- "description": "Connector to create",
- "required": true
- },
"responses": {
- "201": {
+ "200": {
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ConnectorDTO"
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ConnectorToolsDTO"
}
}
},
- "description": "Created"
+ "description": "OK"
},
"400": {
"content": {
@@ -7353,6 +8278,26 @@
},
"description": "Bad Request"
},
+ "403": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Forbidden"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
"409": {
"content": {
"application/json": {
@@ -7363,6 +8308,16 @@
},
"description": "Conflict"
},
+ "422": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Unprocessable Entity"
+ },
"500": {
"content": {
"application/json": {
@@ -7372,6 +8327,26 @@
}
},
"description": "Internal Server Error"
+ },
+ "502": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Gateway"
+ },
+ "503": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Service Unavailable"
}
},
"security": [
@@ -7379,14 +8354,14 @@
"BearerAuth": []
}
],
- "summary": "Create connector",
+ "summary": "Refresh a connector's tool list",
"tags": [
"directory"
]
}
},
- "/v1/gateways/{gateway_id}/connectors/{id}": {
- "delete": {
+ "/v1/gateways/{gateway_id}/connectors": {
+ "get": {
"parameters": [
{
"description": "Connector-gateway install id",
@@ -7396,40 +8371,18 @@
"schema": {
"type": "string"
}
- },
- {
- "description": "Connector UUID",
- "in": "path",
- "name": "id",
- "required": true,
- "schema": {
- "type": "string"
- }
}
],
"responses": {
- "204": {
- "description": "No Content"
- },
- "400": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
- }
- }
- },
- "description": "Bad Request"
- },
- "404": {
+ "200": {
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ "$ref": "#/components/schemas/internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_ConnectorDTO"
}
}
},
- "description": "Not Found"
+ "description": "OK"
},
"500": {
"content": {
@@ -7447,12 +8400,184 @@
"BearerAuth": []
}
],
- "summary": "Delete connector",
+ "summary": "List connectors",
"tags": [
"directory"
]
},
- "get": {
+ "post": {
+ "parameters": [
+ {
+ "description": "Connector-gateway install id",
+ "in": "path",
+ "name": "gateway_id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ {
+ "type": "object"
+ },
+ {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ConnectorWriteRequest",
+ "summary": "body",
+ "description": "Connector to create"
+ }
+ ]
+ }
+ }
+ },
+ "description": "Connector to create",
+ "required": true
+ },
+ "responses": {
+ "201": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ConnectorDTO"
+ }
+ }
+ },
+ "description": "Created"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "409": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Conflict"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Create connector",
+ "tags": [
+ "directory"
+ ]
+ }
+ },
+ "/v1/gateways/{gateway_id}/connectors/{id}": {
+ "delete": {
+ "parameters": [
+ {
+ "description": "Connector-gateway install id",
+ "in": "path",
+ "name": "gateway_id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Connector UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "No Content"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ },
+ "502": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Gateway"
+ },
+ "503": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Service Unavailable"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Delete connector",
+ "tags": [
+ "directory"
+ ]
+ },
+ "get": {
"parameters": [
{
"description": "Connector-gateway install id",
@@ -7526,6 +8651,7 @@
]
},
"put": {
+ "description": "Full replace: resend every mutable field. To keep a connector's secrets, send the auth object a GET returned back unchanged; the read renders each SecretRef, never a secret value. An optional SecretRef left out of the body (token_exchange client_secret, xaa idp_client_secret and target_client_secret) is cleared, which turns a confidential client into a public one. A required SecretRef left out is a 400. Each SecretRef is still checked against the write-side rules, so a kind this server cannot resolve (kubernetes_secret) or a ManagedSecret that no longer exists is a 400.",
"parameters": [
{
"description": "Connector-gateway install id",
@@ -7704,9 +8830,8 @@
]
}
},
- "/v1/gateways/{gateway_id}/discovered-servers": {
- "get": {
- "description": "Lists the MCP servers the cluster is running as candidates a connector could be admitted from, each carrying the connectors on this gateway that already hold its endpoint.",
+ "/v1/gateways/{gateway_id}/connectors/{id}/setup-connection": {
+ "post": {
"parameters": [
{
"description": "Connector-gateway install id",
@@ -7716,6 +8841,15 @@
"schema": {
"type": "string"
}
+ },
+ {
+ "description": "Connector UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
}
],
"responses": {
@@ -7723,13 +8857,23 @@
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.DiscoveredServerListResponse"
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ConnectionDTO"
}
}
},
- "description": "OK"
+ "description": "Existing Connection, setup access re-armed"
},
- "404": {
+ "201": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ConnectionDTO"
+ }
+ }
+ },
+ "description": "Connection created with setup access"
+ },
+ "400": {
"content": {
"application/json": {
"schema": {
@@ -7737,9 +8881,9 @@
}
}
},
- "description": "Not Found"
+ "description": "Bad Request"
},
- "500": {
+ "401": {
"content": {
"application/json": {
"schema": {
@@ -7747,9 +8891,9 @@
}
}
},
- "description": "Internal Server Error"
+ "description": "Unauthorized"
},
- "503": {
+ "403": {
"content": {
"application/json": {
"schema": {
@@ -7757,7 +8901,27 @@
}
}
},
- "description": "Service Unavailable"
+ "description": "Forbidden"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
}
},
"security": [
@@ -7765,26 +8929,93 @@
"BearerAuth": []
}
],
- "summary": "List discovered MCP servers",
+ "summary": "Open my admin setup access to a connector before any group is granted it",
"tags": [
"directory"
]
}
},
- "/v1/groups": {
+ "/v1/gateways/{gateway_id}/discovered-servers": {
"get": {
+ "description": "Lists the MCP servers the cluster is running as candidates a connector could be admitted from, each carrying the connectors on this gateway that already hold its endpoint.",
"parameters": [
{
- "description": "Filter by group name",
- "in": "query",
- "name": "name",
+ "description": "Connector-gateway install id",
+ "in": "path",
+ "name": "gateway_id",
+ "required": true,
"schema": {
"type": "string"
}
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.DiscoveredServerListResponse"
+ }
+ }
+ },
+ "description": "OK"
},
- {
- "description": "Filter by display name",
- "in": "query",
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ },
+ "503": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Service Unavailable"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "List discovered MCP servers",
+ "tags": [
+ "directory"
+ ]
+ }
+ },
+ "/v1/groups": {
+ "get": {
+ "parameters": [
+ {
+ "description": "Filter by group name",
+ "in": "query",
+ "name": "name",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Filter by display name",
+ "in": "query",
"name": "display_name",
"schema": {
"type": "string"
@@ -7937,6 +9168,160 @@
]
}
},
+ "/v1/groups/{group_id}/service-accounts/{id}": {
+ "delete": {
+ "parameters": [
+ {
+ "description": "Group UUID",
+ "in": "path",
+ "name": "group_id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Service account UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "Removed, or was not a member"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "409": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Conflict"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Remove a service account from a group",
+ "tags": [
+ "directory"
+ ]
+ },
+ "put": {
+ "parameters": [
+ {
+ "description": "Group UUID",
+ "in": "path",
+ "name": "group_id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Service account UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "Added, or already a member"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "409": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Conflict"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Add a service account to a group",
+ "tags": [
+ "directory"
+ ]
+ }
+ },
"/v1/groups/{group_id}/subgroups/{child_id}": {
"delete": {
"parameters": [
@@ -8543,7 +9928,23 @@
}
},
{
- "description": "Filter the transitive-users collection by active status (direct_child_groups is unaffected)",
+ "description": "Opaque cursor — pages the service-accounts collection forward (mutually exclusive with service_accounts_before)",
+ "in": "query",
+ "name": "service_accounts_cursor",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Opaque cursor — pages the service-accounts collection backward (mutually exclusive with service_accounts_cursor)",
+ "in": "query",
+ "name": "service_accounts_before",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Filter the transitive-users collection by active status (direct_child_groups and service_accounts are unaffected)",
"in": "query",
"name": "active",
"schema": {
@@ -8551,7 +9952,7 @@
}
},
{
- "description": "Case-insensitive substring search: display_name/user_name/email on the transitive-users collection, display_name/name on the direct-child-groups collection",
+ "description": "Case-insensitive substring search: display_name/user_name/email on the transitive-users collection, display_name/name on the direct-child-groups collection (service_accounts is unaffected)",
"in": "query",
"name": "search",
"schema": {
@@ -10334,6 +11735,16 @@
}
},
"description": "Internal Server Error"
+ },
+ "502": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Gateway"
}
},
"security": [
@@ -10939,10 +12350,7 @@
"content": {
"application/json": {
"schema": {
- "additionalProperties": {
- "type": "string"
- },
- "type": "object"
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
}
}
},
@@ -10952,10 +12360,7 @@
"content": {
"application/json": {
"schema": {
- "additionalProperties": {
- "type": "string"
- },
- "type": "object"
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
}
}
},
@@ -10965,10 +12370,7 @@
"content": {
"application/json": {
"schema": {
- "additionalProperties": {
- "type": "string"
- },
- "type": "object"
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
}
}
},
@@ -12227,13 +13629,14 @@
"schema": {
"enum": [
"user",
- "group"
+ "group",
+ "service_account"
],
"type": "string"
}
},
{
- "description": "Case-insensitive substring match: a user on display name, user name or email; a group on display name or name. Counts stay totals.",
+ "description": "Case-insensitive substring match: a user on display name, user name or email; a group on display name or name; a service account on display name. Counts stay totals.",
"in": "query",
"name": "search",
"schema": {
@@ -12453,86 +13856,217 @@
]
}
},
- "/v1/users": {
+ "/v1/service-accounts": {
"get": {
"parameters": [
{
- "description": "Filter by email address",
+ "description": "Opaque pagination cursor, pages forward (exclusive with before)",
"in": "query",
- "name": "email",
+ "name": "cursor",
"schema": {
"type": "string"
}
},
{
- "description": "Filter by username",
+ "description": "Opaque pagination cursor, pages backward (exclusive with cursor)",
"in": "query",
- "name": "user_name",
+ "name": "before",
"schema": {
"type": "string"
}
},
{
- "description": "Filter by provisioning source (e.g. scim)",
+ "description": "Maximum items to return (default 20, max 200)",
"in": "query",
- "name": "source",
+ "name": "limit",
"schema": {
- "type": "string"
- }
- },
- {
- "description": "Filter by active status",
- "in": "query",
- "name": "active",
- "schema": {
- "type": "boolean"
+ "type": "integer"
}
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_ServiceAccountDTO"
+ }
+ }
+ },
+ "description": "OK"
},
- {
- "description": "Case-insensitive substring search across display_name, user_name, and email",
- "in": "query",
- "name": "search",
- "schema": {
- "type": "string"
- }
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
},
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
{
- "description": "Opaque pagination cursor — pages forward from here (mutually exclusive with before)",
- "in": "query",
- "name": "cursor",
- "schema": {
- "type": "string"
+ "BearerAuth": []
+ }
+ ],
+ "summary": "List service accounts",
+ "tags": [
+ "directory"
+ ]
+ },
+ "post": {
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ {
+ "type": "object"
+ },
+ {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.CreateServiceAccountRequest",
+ "summary": "body",
+ "description": "Display metadata"
+ }
+ ]
+ }
}
},
+ "description": "Display metadata",
+ "required": true
+ },
+ "responses": {
+ "201": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ServiceAccountDTO"
+ }
+ }
+ },
+ "description": "Created"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "401": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Unauthorized"
+ },
+ "403": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Forbidden"
+ },
+ "413": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Request Entity Too Large"
+ },
+ "422": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Unprocessable Entity"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
{
- "description": "Opaque pagination cursor — pages backward from here (mutually exclusive with cursor)",
- "in": "query",
- "name": "before",
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Create a service account",
+ "tags": [
+ "directory"
+ ]
+ }
+ },
+ "/v1/service-accounts/{id}": {
+ "delete": {
+ "parameters": [
+ {
+ "description": "Service account UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
"schema": {
"type": "string"
}
},
{
- "description": "Maximum items to return (default 50, max 200)",
- "in": "query",
- "name": "limit",
+ "description": "ETag from GET /v1/service-accounts/{id}",
+ "in": "header",
+ "name": "If-Match",
+ "required": true,
"schema": {
- "type": "integer"
+ "type": "string"
}
}
],
"responses": {
- "200": {
+ "204": {
+ "description": "Deprovisioned"
+ },
+ "400": {
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_UserDTO"
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
}
}
},
- "description": "OK"
+ "description": "Bad Request"
},
- "400": {
+ "404": {
"content": {
"application/json": {
"schema": {
@@ -12540,7 +14074,37 @@
}
}
},
- "description": "Bad Request"
+ "description": "Not Found"
+ },
+ "409": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Conflict"
+ },
+ "412": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Precondition Failed"
+ },
+ "428": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Precondition Required"
},
"500": {
"content": {
@@ -12558,17 +14122,15 @@
"BearerAuth": []
}
],
- "summary": "List users",
+ "summary": "Deprovision a service account",
"tags": [
"directory"
]
- }
- },
- "/v1/users/{id}": {
+ },
"get": {
"parameters": [
{
- "description": "User UUID",
+ "description": "Service account UUID",
"in": "path",
"name": "id",
"required": true,
@@ -12582,7 +14144,7 @@
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.UserDTO"
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ServiceAccountDTO"
}
}
},
@@ -12624,37 +14186,1785 @@
"BearerAuth": []
}
],
- "summary": "Get user",
+ "summary": "Get a service account",
"tags": [
"directory"
]
- }
- },
- "/v1/users/{id}/groups": {
- "get": {
+ },
+ "put": {
"parameters": [
{
- "description": "User UUID",
+ "description": "Service account UUID",
"in": "path",
"name": "id",
"required": true,
"schema": {
"type": "string"
}
+ },
+ {
+ "description": "ETag from GET /v1/service-accounts/{id}",
+ "in": "header",
+ "name": "If-Match",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
}
],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ {
+ "type": "object"
+ },
+ {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ReplaceServiceAccountRequest",
+ "summary": "body",
+ "description": "Mutable representation"
+ }
+ ]
+ }
+ }
+ },
+ "description": "Mutable representation",
+ "required": true
+ },
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_GroupDTO"
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ServiceAccountDTO"
+ }
+ }
+ },
+ "description": "OK"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "409": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Conflict"
+ },
+ "412": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Precondition Failed"
+ },
+ "413": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Request Entity Too Large"
+ },
+ "422": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Unprocessable Entity"
+ },
+ "428": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Precondition Required"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Replace a service account",
+ "tags": [
+ "directory"
+ ]
+ }
+ },
+ "/v1/service-accounts/{id}/external-bindings": {
+ "get": {
+ "parameters": [
+ {
+ "description": "Service account UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Opaque pagination cursor, pages forward (exclusive with before)",
+ "in": "query",
+ "name": "cursor",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Opaque pagination cursor, pages backward (exclusive with cursor)",
+ "in": "query",
+ "name": "before",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Maximum items to return (default 20, max 200)",
+ "in": "query",
+ "name": "limit",
+ "schema": {
+ "type": "integer"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_ExternalBindingDTO"
+ }
+ }
+ },
+ "description": "OK"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "401": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Unauthorized"
+ },
+ "403": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Forbidden"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "List a service account's external bindings",
+ "tags": [
+ "directory"
+ ]
+ },
+ "post": {
+ "parameters": [
+ {
+ "description": "Service account UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ {
+ "type": "object"
+ },
+ {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.CreateExternalBindingRequest",
+ "summary": "body",
+ "description": "Selector, and the UID to pin"
+ }
+ ]
+ }
+ }
+ },
+ "description": "Selector, and the UID to pin",
+ "required": true
+ },
+ "responses": {
+ "201": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ExternalBindingDTO"
+ }
+ }
+ },
+ "description": "Created"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "401": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Unauthorized"
+ },
+ "403": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Forbidden"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "409": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Conflict"
+ },
+ "413": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Request Entity Too Large"
+ },
+ "422": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Unprocessable Entity"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Bind a service account to a Kubernetes ServiceAccount",
+ "tags": [
+ "directory"
+ ]
+ }
+ },
+ "/v1/service-accounts/{id}/external-bindings/{binding_id}": {
+ "delete": {
+ "parameters": [
+ {
+ "description": "Service account UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "External binding UUID",
+ "in": "path",
+ "name": "binding_id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "Deleted"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "401": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Unauthorized"
+ },
+ "403": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Forbidden"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "409": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Conflict"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Delete an external binding",
+ "tags": [
+ "directory"
+ ]
+ },
+ "get": {
+ "parameters": [
+ {
+ "description": "Service account UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "External binding UUID",
+ "in": "path",
+ "name": "binding_id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ExternalBindingDTO"
+ }
+ }
+ },
+ "description": "OK"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "401": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Unauthorized"
+ },
+ "403": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Forbidden"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Get an external binding",
+ "tags": [
+ "directory"
+ ]
+ }
+ },
+ "/v1/service-accounts/{id}/groups": {
+ "get": {
+ "parameters": [
+ {
+ "description": "Service account UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_GroupDTO"
+ }
+ }
+ },
+ "description": "OK"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Get service account groups",
+ "tags": [
+ "directory"
+ ]
+ }
+ },
+ "/v1/service-accounts/{id}/model-access": {
+ "get": {
+ "parameters": [
+ {
+ "description": "Service account UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ModelAccessExplanationDTO"
+ }
+ }
+ },
+ "description": "OK"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Explain a service account's effective model access",
+ "tags": [
+ "directory"
+ ]
+ }
+ },
+ "/v1/service-accounts/{id}/model-sets": {
+ "get": {
+ "parameters": [
+ {
+ "description": "Service account UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_ModelSetRefDTO"
+ }
+ }
+ },
+ "description": "OK"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "List the Model Sets granted directly to a service account",
+ "tags": [
+ "directory"
+ ]
+ },
+ "put": {
+ "parameters": [
+ {
+ "description": "Service account UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "ETag from GET /v1/service-accounts/{id}/model-sets",
+ "in": "header",
+ "name": "If-Match",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ {
+ "type": "object"
+ },
+ {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ReplaceModelSetGrantsRequest",
+ "summary": "body",
+ "description": "Model Set ids"
+ }
+ ]
+ }
+ }
+ },
+ "description": "Model Set ids",
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_ModelSetRefDTO"
+ }
+ }
+ },
+ "description": "OK"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "409": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Conflict"
+ },
+ "412": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Precondition Failed"
+ },
+ "422": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Unprocessable Entity"
+ },
+ "428": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Precondition Required"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Replace the Model Sets granted directly to a service account",
+ "tags": [
+ "directory"
+ ]
+ }
+ },
+ "/v1/users": {
+ "get": {
+ "parameters": [
+ {
+ "description": "Filter by email address",
+ "in": "query",
+ "name": "email",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Filter by username",
+ "in": "query",
+ "name": "user_name",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Filter by provisioning source (e.g. scim)",
+ "in": "query",
+ "name": "source",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Filter by active status",
+ "in": "query",
+ "name": "active",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ {
+ "description": "Case-insensitive substring search across display_name, user_name, and email",
+ "in": "query",
+ "name": "search",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Opaque pagination cursor — pages forward from here (mutually exclusive with before)",
+ "in": "query",
+ "name": "cursor",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Opaque pagination cursor — pages backward from here (mutually exclusive with cursor)",
+ "in": "query",
+ "name": "before",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Maximum items to return (default 50, max 200)",
+ "in": "query",
+ "name": "limit",
+ "schema": {
+ "type": "integer"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_UserDTO"
+ }
+ }
+ },
+ "description": "OK"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "List users",
+ "tags": [
+ "directory"
+ ]
+ }
+ },
+ "/v1/users/{id}": {
+ "get": {
+ "parameters": [
+ {
+ "description": "User UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.UserDTO"
+ }
+ }
+ },
+ "description": "OK"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Get user",
+ "tags": [
+ "directory"
+ ]
+ }
+ },
+ "/v1/users/{id}/groups": {
+ "get": {
+ "parameters": [
+ {
+ "description": "User UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_GroupDTO"
+ }
+ }
+ },
+ "description": "OK"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Get user groups",
+ "tags": [
+ "directory"
+ ]
+ }
+ },
+ "/v1/users/{id}/metadata": {
+ "delete": {
+ "parameters": [
+ {
+ "description": "User UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "No Content"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Delete user metadata",
+ "tags": [
+ "directory"
+ ]
+ },
+ "get": {
+ "parameters": [
+ {
+ "description": "User UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.MetadataResponse"
+ }
+ }
+ },
+ "description": "OK"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Get user metadata",
+ "tags": [
+ "directory"
+ ]
+ },
+ "put": {
+ "parameters": [
+ {
+ "description": "User UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object"
+ }
+ },
+ "text/plain": {
+ "schema": {
+ "title": "body",
+ "type": "object"
+ }
+ }
+ },
+ "description": "Metadata JSON document",
+ "required": true
+ },
+ "responses": {
+ "204": {
+ "description": "No Content"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Put user metadata",
+ "tags": [
+ "directory"
+ ]
+ }
+ },
+ "/v1/users/{id}/model-access": {
+ "get": {
+ "parameters": [
+ {
+ "description": "User UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ModelAccessExplanationDTO"
+ }
+ }
+ },
+ "description": "OK"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Explain a User's effective model access",
+ "tags": [
+ "directory"
+ ]
+ }
+ },
+ "/v1/users/{id}/model-sets": {
+ "get": {
+ "parameters": [
+ {
+ "description": "User UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_ModelSetRefDTO"
+ }
+ }
+ },
+ "description": "OK"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "List the Model Sets granted directly to a User",
+ "tags": [
+ "directory"
+ ]
+ },
+ "put": {
+ "parameters": [
+ {
+ "description": "User UUID",
+ "in": "path",
+ "name": "id",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "ETag from GET /v1/users/{id}/model-sets",
+ "in": "header",
+ "name": "If-Match",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ {
+ "type": "object"
+ },
+ {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ReplaceModelSetGrantsRequest",
+ "summary": "body",
+ "description": "Model Set ids"
+ }
+ ]
+ }
+ }
+ },
+ "description": "Model Set ids",
+ "required": true
+ },
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_ModelSetRefDTO"
+ }
+ }
+ },
+ "description": "OK"
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "404": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Not Found"
+ },
+ "412": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Precondition Failed"
+ },
+ "422": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Unprocessable Entity"
+ },
+ "428": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Precondition Required"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "Replace the Model Sets granted directly to a User",
+ "tags": [
+ "directory"
+ ]
+ }
+ },
+ "/v1/workload-trusts": {
+ "get": {
+ "parameters": [
+ {
+ "description": "Opaque pagination cursor, pages forward (exclusive with before)",
+ "in": "query",
+ "name": "cursor",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Opaque pagination cursor, pages backward (exclusive with cursor)",
+ "in": "query",
+ "name": "before",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "description": "Maximum items to return (default 20, max 200)",
+ "in": "query",
+ "name": "limit",
+ "schema": {
+ "type": "integer"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_WorkloadTrustDTO"
+ }
+ }
+ },
+ "description": "OK",
+ "headers": {
+ "ETag": {
+ "description": "Strong ETag of this page",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "401": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Unauthorized"
+ },
+ "403": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Forbidden"
+ },
+ "500": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Internal Server Error"
+ }
+ },
+ "security": [
+ {
+ "BearerAuth": []
+ }
+ ],
+ "summary": "List workload trusts",
+ "tags": [
+ "directory"
+ ]
+ },
+ "post": {
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ {
+ "type": "object"
+ },
+ {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.CreateWorkloadTrustRequest",
+ "summary": "body",
+ "description": "Trust"
+ }
+ ]
+ }
+ }
+ },
+ "description": "Trust",
+ "required": true
+ },
+ "responses": {
+ "201": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.WorkloadTrustDTO"
+ }
+ }
+ },
+ "description": "Created",
+ "headers": {
+ "Location": {
+ "description": "Path of the created trust",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Bad Request"
+ },
+ "401": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Unauthorized"
+ },
+ "403": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
}
}
},
- "description": "OK"
+ "description": "Forbidden"
},
- "400": {
+ "409": {
"content": {
"application/json": {
"schema": {
@@ -12662,9 +15972,9 @@
}
}
},
- "description": "Bad Request"
+ "description": "Conflict"
},
- "404": {
+ "413": {
"content": {
"application/json": {
"schema": {
@@ -12672,7 +15982,17 @@
}
}
},
- "description": "Not Found"
+ "description": "Request Entity Too Large"
+ },
+ "422": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Unprocessable Entity"
},
"500": {
"content": {
@@ -12690,28 +16010,37 @@
"BearerAuth": []
}
],
- "summary": "Get user groups",
+ "summary": "Create a workload trust",
"tags": [
"directory"
]
}
},
- "/v1/users/{id}/metadata": {
+ "/v1/workload-trusts/{id}": {
"delete": {
"parameters": [
{
- "description": "User UUID",
+ "description": "Workload trust UUID",
"in": "path",
"name": "id",
"required": true,
"schema": {
"type": "string"
}
+ },
+ {
+ "description": "ETag from GET /v1/workload-trusts/{id}",
+ "in": "header",
+ "name": "If-Match",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
}
],
"responses": {
"204": {
- "description": "No Content"
+ "description": "Deleted"
},
"400": {
"content": {
@@ -12723,7 +16052,7 @@
},
"description": "Bad Request"
},
- "500": {
+ "401": {
"content": {
"application/json": {
"schema": {
@@ -12731,43 +16060,19 @@
}
}
},
- "description": "Internal Server Error"
- }
- },
- "security": [
- {
- "BearerAuth": []
- }
- ],
- "summary": "Delete user metadata",
- "tags": [
- "directory"
- ]
- },
- "get": {
- "parameters": [
- {
- "description": "User UUID",
- "in": "path",
- "name": "id",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
+ "description": "Unauthorized"
+ },
+ "403": {
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.MetadataResponse"
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
}
}
},
- "description": "OK"
+ "description": "Forbidden"
},
- "400": {
+ "404": {
"content": {
"application/json": {
"schema": {
@@ -12775,9 +16080,9 @@
}
}
},
- "description": "Bad Request"
+ "description": "Not Found"
},
- "404": {
+ "409": {
"content": {
"application/json": {
"schema": {
@@ -12785,9 +16090,9 @@
}
}
},
- "description": "Not Found"
+ "description": "Conflict"
},
- "500": {
+ "412": {
"content": {
"application/json": {
"schema": {
@@ -12795,53 +16100,9 @@
}
}
},
- "description": "Internal Server Error"
- }
- },
- "security": [
- {
- "BearerAuth": []
- }
- ],
- "summary": "Get user metadata",
- "tags": [
- "directory"
- ]
- },
- "put": {
- "parameters": [
- {
- "description": "User UUID",
- "in": "path",
- "name": "id",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "type": "object"
- }
- },
- "text/plain": {
- "schema": {
- "title": "body",
- "type": "object"
- }
- }
- },
- "description": "Metadata JSON document",
- "required": true
- },
- "responses": {
- "204": {
- "description": "No Content"
+ "description": "Precondition Failed"
},
- "400": {
+ "428": {
"content": {
"application/json": {
"schema": {
@@ -12849,7 +16110,7 @@
}
}
},
- "description": "Bad Request"
+ "description": "Precondition Required"
},
"500": {
"content": {
@@ -12867,17 +16128,15 @@
"BearerAuth": []
}
],
- "summary": "Put user metadata",
+ "summary": "Delete a workload trust",
"tags": [
"directory"
]
- }
- },
- "/v1/users/{id}/model-access": {
+ },
"get": {
"parameters": [
{
- "description": "User UUID",
+ "description": "Workload trust UUID",
"in": "path",
"name": "id",
"required": true,
@@ -12891,11 +16150,19 @@
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ModelAccessExplanationDTO"
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.WorkloadTrustDTO"
}
}
},
- "description": "OK"
+ "description": "OK",
+ "headers": {
+ "ETag": {
+ "description": "Strong ETag to send as If-Match on PUT and DELETE",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
},
"400": {
"content": {
@@ -12907,7 +16174,7 @@
},
"description": "Bad Request"
},
- "500": {
+ "401": {
"content": {
"application/json": {
"schema": {
@@ -12915,45 +16182,9 @@
}
}
},
- "description": "Internal Server Error"
- }
- },
- "security": [
- {
- "BearerAuth": []
- }
- ],
- "summary": "Explain a User's effective model access",
- "tags": [
- "directory"
- ]
- }
- },
- "/v1/users/{id}/model-sets": {
- "get": {
- "parameters": [
- {
- "description": "User UUID",
- "in": "path",
- "name": "id",
- "required": true,
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_ModelSetRefDTO"
- }
- }
- },
- "description": "OK"
+ "description": "Unauthorized"
},
- "400": {
+ "403": {
"content": {
"application/json": {
"schema": {
@@ -12961,7 +16192,7 @@
}
}
},
- "description": "Bad Request"
+ "description": "Forbidden"
},
"404": {
"content": {
@@ -12989,7 +16220,7 @@
"BearerAuth": []
}
],
- "summary": "List the Model Sets granted directly to a User",
+ "summary": "Get a workload trust",
"tags": [
"directory"
]
@@ -12997,7 +16228,7 @@
"put": {
"parameters": [
{
- "description": "User UUID",
+ "description": "Workload trust UUID",
"in": "path",
"name": "id",
"required": true,
@@ -13006,7 +16237,7 @@
}
},
{
- "description": "ETag from GET /v1/users/{id}/model-sets",
+ "description": "ETag from GET /v1/workload-trusts/{id}",
"in": "header",
"name": "If-Match",
"required": true,
@@ -13024,15 +16255,15 @@
"type": "object"
},
{
- "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ReplaceModelSetGrantsRequest",
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.ReplaceWorkloadTrustRequest",
"summary": "body",
- "description": "Model Set ids"
+ "description": "Trust"
}
]
}
}
},
- "description": "Model Set ids",
+ "description": "Trust",
"required": true
},
"responses": {
@@ -13040,11 +16271,19 @@
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/internal_directory_app.ListResponse-github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1_ModelSetRefDTO"
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_directory_v1.WorkloadTrustDTO"
}
}
},
- "description": "OK"
+ "description": "OK",
+ "headers": {
+ "ETag": {
+ "description": "Strong ETag of the trust as written",
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
},
"400": {
"content": {
@@ -13056,6 +16295,26 @@
},
"description": "Bad Request"
},
+ "401": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Unauthorized"
+ },
+ "403": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Forbidden"
+ },
"404": {
"content": {
"application/json": {
@@ -13066,6 +16325,16 @@
},
"description": "Not Found"
},
+ "409": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Conflict"
+ },
"412": {
"content": {
"application/json": {
@@ -13076,6 +16345,16 @@
},
"description": "Precondition Failed"
},
+ "413": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/github_com_stacklok_stacklok-enterprise-platform_enterprise_toolhive-enterprise_contracts_common_v1.ErrorResponse"
+ }
+ }
+ },
+ "description": "Request Entity Too Large"
+ },
"422": {
"content": {
"application/json": {
@@ -13112,7 +16391,7 @@
"BearerAuth": []
}
],
- "summary": "Replace the Model Sets granted directly to a User",
+ "summary": "Replace a workload trust",
"tags": [
"directory"
]