@artifact-keeper/sdk 1.1.9-rc.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/types.gen.ts CHANGED
@@ -198,6 +198,14 @@ export type ArtifactLabelsListResponse = {
198
198
  };
199
199
 
200
200
  export type ArtifactListResponse = {
201
+ /**
202
+ * Maven component grouping. Only present when `group_by=maven_component`.
203
+ */
204
+ components?: Array<MavenComponentResponse> | null;
205
+ /**
206
+ * Docker tag grouping. Only present when `group_by=docker_tag`.
207
+ */
208
+ docker_tags?: Array<DockerTagResponse> | null;
201
209
  items: Array<ArtifactResponse>;
202
210
  pagination: Pagination;
203
211
  };
@@ -210,6 +218,21 @@ export type ArtifactMetadataResponse = {
210
218
  };
211
219
 
212
220
  export type ArtifactResponse = {
221
+ /**
222
+ * When the proxy cache entry for this artifact was last written.
223
+ * Only populated for Remote (proxy) repositories whose proxy service is
224
+ * configured AND that have a cache-metadata blob for this path. None
225
+ * for Local / Virtual / Staging repos and for Remote repos whose cache
226
+ * hasn't been populated yet (e.g. an artifact that exists as a DB row
227
+ * from a direct upload but has never been fetched through the proxy).
228
+ * (#1541)
229
+ */
230
+ cache_cached_at?: string | null;
231
+ /**
232
+ * When the proxy cache entry for this artifact will expire and be
233
+ * re-validated against upstream. Same gating as `cache_cached_at`. (#1541)
234
+ */
235
+ cache_expires_at?: string | null;
213
236
  checksum_sha256: string;
214
237
  content_type: string;
215
238
  created_at: string;
@@ -247,6 +270,14 @@ export type AssessmentResult = {
247
270
  };
248
271
 
249
272
  export type AssignRepoRequest = {
273
+ /**
274
+ * Optional JSONB filter constraining which artifacts in the repository
275
+ * get replicated. Shape: `{"include_patterns": ["^v\\d+\\."], "exclude_patterns": [".*-SNAPSHOT$"]}`.
276
+ * Null/absent means replicate everything.
277
+ */
278
+ replication_filter: {
279
+ [key: string]: unknown;
280
+ };
250
281
  replication_mode?: string | null;
251
282
  replication_schedule?: string | null;
252
283
  repository_id: string;
@@ -257,6 +288,25 @@ export type AssignRoleRequest = {
257
288
  role_id: string;
258
289
  };
259
290
 
291
+ /**
292
+ * Authentication provider availability.
293
+ */
294
+ export type AuthConfig = {
295
+ /**
296
+ * Whether an LDAP directory is configured.
297
+ */
298
+ ldap_enabled: boolean;
299
+ /**
300
+ * Whether an OIDC provider is configured.
301
+ */
302
+ oidc_enabled: boolean;
303
+ /**
304
+ * Whether SAML SSO is configured (derived from the SSO admin settings in the DB,
305
+ * but for this endpoint we report whether the OIDC issuer is set as a proxy).
306
+ */
307
+ sso_enabled: boolean;
308
+ };
309
+
260
310
  export type BackupListResponse = {
261
311
  items: Array<BackupResponse>;
262
312
  total: number;
@@ -384,7 +434,11 @@ export type BulkPromoteRequest = {
384
434
  artifact_ids: Array<string>;
385
435
  notes?: string | null;
386
436
  skip_policy_check?: boolean;
387
- target_repository: string;
437
+ /**
438
+ * Target release repository key. When omitted, the staging repository's
439
+ * linked release target (from `repository_config`) is used instead.
440
+ */
441
+ target_repository?: string | null;
388
442
  };
389
443
 
390
444
  export type BulkPromotionResponse = {
@@ -646,6 +700,19 @@ export type CreateConnectionRequest = {
646
700
  url: string;
647
701
  };
648
702
 
703
+ export type CreateEmailSubscriptionRequest = {
704
+ enabled?: boolean;
705
+ /**
706
+ * Event-type tokens to listen for. Must be drawn from `VALID_EVENT_TYPES`.
707
+ */
708
+ event_types: Array<string>;
709
+ /**
710
+ * Email addresses to deliver matching events to. Bounded length;
711
+ * see `MAX_RECIPIENTS_PER_SUBSCRIPTION` for the operator-facing limit.
712
+ */
713
+ recipients: Array<string>;
714
+ };
715
+
649
716
  export type CreateGateRequest = {
650
717
  action?: string;
651
718
  description?: string | null;
@@ -719,7 +786,17 @@ export type CreateOidcConfigRequest = {
719
786
  client_secret: string;
720
787
  is_enabled?: boolean | null;
721
788
  issuer_url: string;
789
+ /**
790
+ * When `true`, OIDC group claim values are reflected as Artifact Keeper
791
+ * group memberships (auto-creating groups on first sight). Defaults to
792
+ * `false` to preserve legacy role-mapping behavior.
793
+ */
794
+ map_groups_to_groups?: boolean | null;
722
795
  name: string;
796
+ /**
797
+ * Enable PKCE (S256) on the authorization request. Defaults to `true`.
798
+ */
799
+ pkce_enabled?: boolean | null;
723
800
  scopes?: Array<string> | null;
724
801
  };
725
802
 
@@ -733,7 +810,7 @@ export type CreatePermissionRequest = {
733
810
 
734
811
  export type CreatePolicyRequest = {
735
812
  block_on_fail: boolean;
736
- block_unscanned: boolean;
813
+ block_unscanned?: boolean;
737
814
  max_artifact_age_days?: number | null;
738
815
  max_severity: string;
739
816
  min_staging_hours?: number | null;
@@ -742,7 +819,51 @@ export type CreatePolicyRequest = {
742
819
  require_signature?: boolean;
743
820
  };
744
821
 
822
+ /**
823
+ * Request to create an access token scoped to a repository.
824
+ */
825
+ export type CreateRepoTokenRequest = {
826
+ /**
827
+ * Optional human-readable description.
828
+ */
829
+ description?: string | null;
830
+ /**
831
+ * Number of days until the token expires (1-365). Omit for no expiration.
832
+ */
833
+ expires_in_days?: number | null;
834
+ /**
835
+ * Display name for the token.
836
+ */
837
+ name: string;
838
+ /**
839
+ * Permission scopes for the token.
840
+ */
841
+ scopes: Array<string>;
842
+ };
843
+
844
+ /**
845
+ * Response returned when a repository token is created. The `token` field
846
+ * contains the plaintext value and is only shown once.
847
+ */
848
+ export type CreateRepoTokenResponse = {
849
+ id: string;
850
+ name: string;
851
+ repository_key: string;
852
+ /**
853
+ * The full token value (only returned at creation time).
854
+ */
855
+ token: string;
856
+ };
857
+
745
858
  export type CreateRepositoryRequest = {
859
+ /**
860
+ * Alias for `is_public`. When set to true, anonymous users can download
861
+ * artifacts from this repository without authentication. Useful for remote
862
+ * (pull-through cache) repositories that proxy public upstream registries.
863
+ * If both `is_public` and `allow_anonymous_access` are provided,
864
+ * `allow_anonymous_access` takes precedence.
865
+ */
866
+ allow_anonymous_access?: boolean | null;
746
867
  description?: string | null;
747
868
  format: string;
748
869
  /**
@@ -764,6 +885,12 @@ export type CreateRepositoryRequest = {
764
885
  */
765
886
  member_repos?: Array<CreateVirtualMemberInput> | null;
766
887
  name: string;
888
+ /**
889
+ * When true, direct user uploads to this repository are rejected:
890
+ * artifacts must arrive via the promotion path. Admin-only to set.
891
+ * Defaults to false (no behavior change for existing repositories).
892
+ */
893
+ promotion_only?: boolean | null;
767
894
  quota_bytes?: number | null;
768
895
  repo_type: string;
769
896
  /**
@@ -830,10 +957,36 @@ export type CreateServiceAccountRequest = {
830
957
  };
831
958
 
832
959
  export type CreateSessionRequest = {
960
+ /**
961
+ * Source artifact metadata for peer replication.
962
+ */
963
+ artifact_metadata?: unknown;
964
+ /**
965
+ * Source artifact metadata format for peer replication.
966
+ */
967
+ artifact_metadata_format?: string | null;
968
+ /**
969
+ * Source artifact metadata properties for peer replication.
970
+ */
971
+ artifact_metadata_properties?: unknown;
972
+ /**
973
+ * Artifact name to persist when the upload completes.
974
+ *
975
+ * Optional for regular client uploads. Peer replication sets this from
976
+ * the source artifact row so chunked replication preserves metadata.
977
+ */
978
+ artifact_name?: string | null;
833
979
  /**
834
980
  * Path within the repository (e.g. "images/vm.ova")
835
981
  */
836
982
  artifact_path: string;
983
+ /**
984
+ * Artifact version to persist when the upload completes.
985
+ *
986
+ * Optional for regular client uploads. Peer replication sets this from
987
+ * the source artifact row so chunked replication preserves metadata.
988
+ */
989
+ artifact_version?: string | null;
837
990
  /**
838
991
  * Expected SHA256 checksum of the complete file
839
992
  */
@@ -846,6 +999,14 @@ export type CreateSessionRequest = {
846
999
  * MIME content type (default "application/octet-stream")
847
1000
  */
848
1001
  content_type?: string | null;
1002
+ /**
1003
+ * Source package description for peer replication.
1004
+ */
1005
+ package_description?: string | null;
1006
+ /**
1007
+ * Source package catalog metadata for peer replication.
1008
+ */
1009
+ package_metadata?: unknown;
849
1010
  /**
850
1011
  * Repository key (e.g. "my-repo")
851
1012
  */
@@ -869,6 +1030,13 @@ export type CreateSyncPolicyPayload = {
869
1030
  };
870
1031
  description?: string;
871
1032
  enabled?: boolean;
1033
+ /**
1034
+ * Convenience glob filter (e.g. `"*.tar.gz"`). When set, it is folded
1035
+ * into `artifact_filter.include_paths` so only matching artifact paths
1036
+ * are eligible for sync. Ignored if `artifact_filter.include_paths` is
1037
+ * already provided.
1038
+ */
1039
+ filter?: string | null;
872
1040
  name: string;
873
1041
  peer_selector?: {
874
1042
  [key: string]: unknown;
@@ -931,12 +1099,27 @@ export type CreateVirtualMemberInput = {
931
1099
  };
932
1100
 
933
1101
  export type CreateWebhookRequest = {
1102
+ /**
1103
+ * Pinned event payload version. Defaults to "2026-04-01" when omitted.
1104
+ * Must match a value in `SUPPORTED_EVENT_VERSIONS` or the request is
1105
+ * rejected with HTTP 422.
1106
+ */
1107
+ event_schema_version?: string | null;
934
1108
  events: Array<string>;
935
1109
  headers?: {
936
1110
  [key: string]: unknown;
937
1111
  } | null;
938
1112
  name: string;
1113
+ /**
1114
+ * Payload layout for the target platform (default: generic).
1115
+ */
1116
+ payload_template?: PayloadTemplate;
939
1117
  repository_id?: string | null;
1118
+ /**
1119
+ * Optional caller-supplied secret. When omitted the server generates a
1120
+ * fresh `whsec_*` secret. Either way the raw value is returned in the
1121
+ * 201 response body exactly once and is unrecoverable thereafter.
1122
+ */
940
1123
  secret?: string | null;
941
1124
  url: string;
942
1125
  };
@@ -1006,17 +1189,47 @@ export type CveTimelineEntry = {
1006
1189
 
1007
1190
  /**
1008
1191
  * CVE trends summary.
1192
+ *
1193
+ * #1446: the security-tests `cve-history` suite probes the trends body for
1194
+ * any of `total`, `count`, `critical`, or `high` to confirm the response
1195
+ * carries aggregate counts (PR #1385 fixed `cve-history` but the trends
1196
+ * shape was not aligned). The original field set (`total_cves`,
1197
+ * `critical_count`, ...) is retained for openapi consumers; the bare
1198
+ * `total`/`critical`/`high`/`medium`/`low` aliases are added alongside so
1199
+ * both shape contracts are satisfied without breaking existing clients.
1200
+ * `#[serde(default)]` keeps deserialization working when the alias fields
1201
+ * are absent (older payloads, tests that build the struct via field init).
1009
1202
  */
1010
1203
  export type CveTrends = {
1011
1204
  acknowledged_cves: number;
1012
1205
  avg_days_to_fix?: number | null;
1206
+ /**
1207
+ * Alias of `critical_count` (#1446).
1208
+ */
1209
+ critical?: number;
1013
1210
  critical_count: number;
1014
1211
  fixed_cves: number;
1212
+ /**
1213
+ * Alias of `high_count` (#1446).
1214
+ */
1215
+ high?: number;
1015
1216
  high_count: number;
1217
+ /**
1218
+ * Alias of `low_count` (#1446).
1219
+ */
1220
+ low?: number;
1016
1221
  low_count: number;
1222
+ /**
1223
+ * Alias of `medium_count` (#1446).
1224
+ */
1225
+ medium?: number;
1017
1226
  medium_count: number;
1018
1227
  open_cves: number;
1019
1228
  timeline: Array<CveTimelineEntry>;
1229
+ /**
1230
+ * Alias of `total_cves` (#1446).
1231
+ */
1232
+ total?: number;
1020
1233
  total_cves: number;
1021
1234
  };
1022
1235
 
@@ -1074,6 +1287,79 @@ export type DiscoverablePeerResponse = {
1074
1287
  status: string;
1075
1288
  };
1076
1289
 
1290
+ /**
1291
+ * A Docker/OCI tag grouped by (image, tag).
1292
+ *
1293
+ * `total_size_bytes` is the server-side aggregation of the manifest body
1294
+ * plus every referenced layer blob. This is what the UI should display
1295
+ * as the on-disk image size; the previous client-side aggregation that
1296
+ * only summed the manifest body itself reported a few kilobytes for
1297
+ * images that are hundreds of megabytes on disk (artifact-keeper#1193).
1298
+ *
1299
+ * For multi-arch image indexes the size is the sum across all per-arch
1300
+ * child manifests recorded in `oci_manifest_refs`, so an `amd64+arm64`
1301
+ * index reports the combined storage cost.
1302
+ */
1303
+ export type DockerTagResponse = {
1304
+ /**
1305
+ * Representative manifest artifact ID.
1306
+ */
1307
+ id: string;
1308
+ /**
1309
+ * Image name (no registry host, no tag). Maps to the OCI v2 `<name>`
1310
+ * path segment, which may include slashes (e.g. `library/postgres`).
1311
+ */
1312
+ image: string;
1313
+ /**
1314
+ * Whether this manifest is a multi-arch image index.
1315
+ */
1316
+ is_index: boolean;
1317
+ /**
1318
+ * Last push (or update) timestamp from the underlying `oci_tags` row.
1319
+ */
1320
+ last_pushed_at: string;
1321
+ /**
1322
+ * Number of layer blobs referenced by the manifest. For image indexes
1323
+ * this is the sum of layer counts across child manifests. `0` when
1324
+ * the manifest could not be parsed.
1325
+ */
1326
+ layer_count: number;
1327
+ /**
1328
+ * Manifest content digest (e.g. `sha256:abcdef...`).
1329
+ */
1330
+ manifest_digest: string;
1331
+ /**
1332
+ * Repository key this tag belongs to.
1333
+ */
1334
+ repository_key: string;
1335
+ /**
1336
+ * Rolled-up scan status across all scanners configured for this
1337
+ * artifact. `None` when the artifact has never been scanned.
1338
+ *
1339
+ * Values surface the aggregate state, not a single scanner's row
1340
+ * (see #1497). One of:
1341
+ *
1342
+ * * `pending` / `running` -- at least one scanner is still in flight
1343
+ * * `completed` -- every per-scan-type latest row is `completed`
1344
+ * * `failed` -- every per-scan-type latest row is `failed`
1345
+ * * `partial` -- mixed: at least one `completed` AND at least one
1346
+ * `failed`. A green generic scanner (e.g. grype) no longer hides
1347
+ * a failed format-native scanner (e.g. incus) behind a
1348
+ * `completed` label.
1349
+ */
1350
+ scan_status?: string | null;
1351
+ /**
1352
+ * Tag string (e.g. `16-alpine`). Never a `sha256:...` digest;
1353
+ * digest-only references are filtered out of the grouping.
1354
+ */
1355
+ tag: string;
1356
+ /**
1357
+ * Total size in bytes of the manifest plus all referenced layer blobs.
1358
+ * For image indexes, this sums across child manifests.
1359
+ */
1360
+ total_size_bytes: number;
1361
+ };
1362
+
1077
1363
  /**
1078
1364
  * Download trend data point.
1079
1365
  */
@@ -1275,8 +1561,31 @@ export type DtProjectMetrics = {
1275
1561
  vulnerabilities?: number | null;
1276
1562
  };
1277
1563
 
1564
+ /**
1565
+ * Dependency-Track integration status surfaced to the frontend.
1566
+ *
1567
+ * `healthy` is the boolean the existing UI already binds to. The new
1568
+ * `error_status` and `error_message` fields let the UI distinguish a
1569
+ * genuine "DT replied OK with no findings" state from "DT is down or
1570
+ * misconfigured" (issue #963). When `healthy = true` both error fields
1571
+ * are None; when `healthy = false`:
1572
+ * - `error_status = Some(401)`: auth failure (check API key)
1573
+ * - `error_status = Some(5xx)`: upstream is broken
1574
+ * - `error_status = None`: transport failure (DT pod unreachable)
1575
+ * - `error_message`: operator-facing failure description
1576
+ */
1278
1577
  export type DtStatusResponse = {
1279
1578
  enabled: boolean;
1579
+ /**
1580
+ * Human-readable explanation when `healthy = false`. Safe to surface
1581
+ * in the UI; does not leak credentials.
1582
+ */
1583
+ error_message?: string | null;
1584
+ /**
1585
+ * Upstream HTTP status if the health probe got a response, else None.
1586
+ * Only populated when `healthy = false`.
1587
+ */
1588
+ error_status?: number | null;
1280
1589
  healthy: boolean;
1281
1590
  url?: string | null;
1282
1591
  };
@@ -1295,6 +1604,20 @@ export type DtVulnerability = {
1295
1604
  vulnId: string;
1296
1605
  };
1297
1606
 
1607
+ export type EmailSubscriptionListResponse = {
1608
+ subscriptions: Array<EmailSubscriptionResponse>;
1609
+ };
1610
+
1611
+ export type EmailSubscriptionResponse = {
1612
+ created_at: string;
1613
+ enabled: boolean;
1614
+ event_types: Array<string>;
1615
+ id: string;
1616
+ recipients: Array<string>;
1617
+ repository_id?: string | null;
1618
+ updated_at: string;
1619
+ };
1620
+
1298
1621
  /**
1299
1622
  * Standard error response body returned by all endpoints on failure.
1300
1623
  */
@@ -1371,6 +1694,13 @@ export type FindingResponse = {
1371
1694
  title: string;
1372
1695
  };
1373
1696
 
1697
+ /**
1698
+ * Response for force password change
1699
+ */
1700
+ export type ForcePasswordChangeResponse = {
1701
+ message: string;
1702
+ };
1703
+
1374
1704
  /**
1375
1705
  * Format handler response with additional computed fields.
1376
1706
  */
@@ -1517,7 +1847,7 @@ export type GrowthSummary = {
1517
1847
  export type HealthChecks = {
1518
1848
  database: CheckStatus;
1519
1849
  ldap?: null | CheckStatus;
1520
- meilisearch?: null | CheckStatus;
1850
+ opensearch?: null | CheckStatus;
1521
1851
  security_scanner?: null | CheckStatus;
1522
1852
  storage: CheckStatus;
1523
1853
  };
@@ -1584,6 +1914,23 @@ export type InstallFromLocalRequest = {
1584
1914
  path: string;
1585
1915
  };
1586
1916
 
1917
+ export type InvalidateCacheQuery = {
1918
+ /**
1919
+ * Artifact path to evict from the proxy cache. Same shape as the path
1920
+ * segment of `GET /api/v1/repositories/{key}/artifacts/{path}`.
1921
+ * Path-traversal segments such as `..` are rejected by
1922
+ * `ProxyService::cache_storage_key` (covered by
1923
+ * `test_invalidate_cache_by_key_rejects_invalid_path`).
1924
+ */
1925
+ path: string;
1926
+ };
1927
+
1928
+ export type InvalidateCacheResponse = {
1929
+ invalidated: boolean;
1930
+ path: string;
1931
+ repository_key: string;
1932
+ };
1933
+
1587
1934
  export type IssueResponse = {
1588
1935
  artifact_id: string;
1589
1936
  category: string;
@@ -1701,6 +2048,19 @@ export type LifecyclePolicy = {
1701
2048
  };
1702
2049
 
1703
2050
  export type ListArtifactsQuery = {
2051
+ /**
2052
+ * Server-side artifact grouping.
2053
+ *
2054
+ * Supported values:
2055
+ * - `maven_component`: Maven/Gradle artifacts are grouped by
2056
+ * groupId, artifactId, and version. Individual files (jar, pom,
2057
+ * checksums) appear in the `artifact_files` array of each component.
2058
+ * - `docker_tag`: Docker/OCI artifacts are grouped by (image, tag),
2059
+ * with `total_size_bytes` summed across the manifest config and
2060
+ * referenced layer blobs. The grouped rows are returned in the
2061
+ * `docker_tags` array.
2062
+ */
2063
+ group_by?: string | null;
1704
2064
  page?: number | null;
1705
2065
  path_prefix?: string | null;
1706
2066
  per_page?: number | null;
@@ -1802,6 +2162,55 @@ export type MatchedRepoSchema = {
1802
2162
  key: string;
1803
2163
  };
1804
2164
 
2165
+ /**
2166
+ * A Maven component grouped by GAV (groupId, artifactId, version).
2167
+ *
2168
+ * Each component collects the individual files (jar, pom, checksums, etc.)
2169
+ * that share the same Maven coordinates.
2170
+ */
2171
+ export type MavenComponentResponse = {
2172
+ /**
2173
+ * Individual filenames belonging to this component.
2174
+ */
2175
+ artifact_files: Array<string>;
2176
+ /**
2177
+ * Maven artifactId (e.g. `junit-jupiter-api`).
2178
+ */
2179
+ artifact_id: string;
2180
+ /**
2181
+ * Earliest creation timestamp among the component files.
2182
+ */
2183
+ created_at: string;
2184
+ /**
2185
+ * Total download count across all files in this component.
2186
+ */
2187
+ download_count: number;
2188
+ /**
2189
+ * Repository format (always `maven` or `gradle`).
2190
+ */
2191
+ format: string;
2192
+ /**
2193
+ * Maven groupId with dots (e.g. `org.junit.jupiter`).
2194
+ */
2195
+ group_id: string;
2196
+ /**
2197
+ * Representative artifact ID (the first file in the group).
2198
+ */
2199
+ id: string;
2200
+ /**
2201
+ * Repository key this component belongs to.
2202
+ */
2203
+ repository_key: string;
2204
+ /**
2205
+ * Total size in bytes across all files in this component.
2206
+ */
2207
+ size_bytes: number;
2208
+ /**
2209
+ * Maven version string (e.g. `5.11.0`).
2210
+ */
2211
+ version: string;
2212
+ };
2213
+
1805
2214
  export type MembersRequest = {
1806
2215
  user_ids: Array<string>;
1807
2216
  };
@@ -1928,6 +2337,83 @@ export type NetworkProfileBody = {
1928
2337
  sync_window_timezone?: string | null;
1929
2338
  };
1930
2339
 
2340
+ /**
2341
+ * Read-only OCI blob storage footprint report (issue #1408).
2342
+ *
2343
+ * This is a **reporting-only** view. It performs no deletion and takes no
2344
+ * locks. It surfaces how much storage the tracked `oci_blobs` rows
2345
+ * account for so operators can see the magnitude of un-reclaimed blob
2346
+ * layers before any garbage-collection mechanism is enabled.
2347
+ *
2348
+ * It deliberately does NOT attempt to classify which blobs are
2349
+ * "reclaimable orphans": that requires a manifest -> blob reference table
2350
+ * that does not yet exist in the schema, and any per-`(repository_id,
2351
+ * digest)` orphan heuristic would mis-handle the cross-repo dedup case
2352
+ * (multiple `oci_blobs` rows, one physical object) and report in-use
2353
+ * blobs as reclaimable. The numbers here are exact aggregates only.
2354
+ */
2355
+ export type OciBlobFootprintReport = {
2356
+ /**
2357
+ * Distinct digests older than `grace_hours` (eligible to be *considered*
2358
+ * by a future GC sweep once a reference table exists). Reporting only.
2359
+ */
2360
+ aged_distinct_digests: number;
2361
+ /**
2362
+ * Physical bytes (distinct-digest) older than `grace_hours`.
2363
+ */
2364
+ aged_physical_bytes: number;
2365
+ /**
2366
+ * Number of distinct blob digests (content-addressed identities). When
2367
+ * this is smaller than `total_blob_rows`, the difference is cross-repo
2368
+ * deduplication: rows that share one physical storage object.
2369
+ */
2370
+ distinct_digests: number;
2371
+ /**
2372
+ * Grace window (hours) applied to the `aged_*` figures below.
2373
+ */
2374
+ grace_hours: number;
2375
+ /**
2376
+ * Sum of `size_bytes` over every `oci_blobs` row. Double-counts
2377
+ * deduplicated blobs once per referencing repository.
2378
+ */
2379
+ logical_bytes: number;
2380
+ /**
2381
+ * Per-repository logical footprint, largest `logical_bytes` first.
2382
+ */
2383
+ per_repository: Array<OciBlobRepoFootprint>;
2384
+ /**
2385
+ * Sum of `size_bytes` counting each distinct digest exactly once. This
2386
+ * approximates the physical bytes occupied in the storage backend.
2387
+ */
2388
+ physical_bytes: number;
2389
+ /**
2390
+ * Total number of `oci_blobs` rows across all repositories.
2391
+ */
2392
+ total_blob_rows: number;
2393
+ };
2394
+
2395
+ /**
2396
+ * Per-repository row in the OCI blob footprint report.
2397
+ */
2398
+ export type OciBlobRepoFootprint = {
2399
+ /**
2400
+ * Number of `oci_blobs` rows attributed to this repository.
2401
+ */
2402
+ blob_rows: number;
2403
+ /**
2404
+ * Sum of `oci_blobs.size_bytes` for this repository's rows. Because OCI
2405
+ * blob storage is content-addressed and deduplicated across repos, the
2406
+ * same physical bytes can be counted under more than one repository
2407
+ * here; see [`OciBlobFootprintReport::physical_bytes`] for the
2408
+ * dedup-aware total.
2409
+ */
2410
+ logical_bytes: number;
2411
+ /**
2412
+ * Repository id owning these `oci_blobs` rows.
2413
+ */
2414
+ repository_id: string;
2415
+ };
2416
+
1931
2417
  export type OidcConfigResponse = {
1932
2418
  attribute_mapping: {
1933
2419
  [key: string]: unknown;
@@ -1939,7 +2425,9 @@ export type OidcConfigResponse = {
1939
2425
  id: string;
1940
2426
  is_enabled: boolean;
1941
2427
  issuer_url: string;
2428
+ map_groups_to_groups: boolean;
1942
2429
  name: string;
2430
+ pkce_enabled: boolean;
1943
2431
  scopes: Array<string>;
1944
2432
  updated_at: string;
1945
2433
  };
@@ -2040,6 +2528,15 @@ export type PaginationInfo = {
2040
2528
  total_pages: number;
2041
2529
  };
2042
2530
 
2531
+ /**
2532
+ * Supported webhook payload templates.
2533
+ *
2534
+ * Controls how the outgoing JSON body is structured when delivering a
2535
+ * webhook. The `Generic` variant preserves backward compatibility with the
2536
+ * original flat JSON format.
2537
+ */
2538
+ export type PayloadTemplate = 'generic' | 'slack' | 'microsoft_teams' | 'discord' | 'mattermost';
2539
+
2043
2540
  export type PeerInstanceListResponse = {
2044
2541
  items: Array<PeerInstanceResponse>;
2045
2542
  total: number;
@@ -2139,6 +2636,23 @@ export type PermissionRow = {
2139
2636
  updated_at: string;
2140
2637
  };
2141
2638
 
2639
+ /**
2640
+ * Fine-grained permissions enforcement status.
2641
+ */
2642
+ export type PermissionsConfig = {
2643
+ /**
2644
+ * Whether those rules are actively enforced on API requests.
2645
+ * The permission-check middleware and handler guards are wired in,
2646
+ * so this is `true` when the server is running.
2647
+ */
2648
+ enforcement_enabled: boolean;
2649
+ /**
2650
+ * Whether the permissions table (from migration 018) has any rows.
2651
+ * When true, an administrator has configured permission rules.
2652
+ */
2653
+ rules_exist: boolean;
2654
+ };
2655
+
2142
2656
  export type PluginConfigResponse = {
2143
2657
  config: {
2144
2658
  [key: string]: unknown;
@@ -2181,6 +2695,26 @@ export type PluginResponse = {
2181
2695
  version: string;
2182
2696
  };
2183
2697
 
2698
+ /**
2699
+ * Plugin signature-verification (supply-chain) policy status.
2700
+ *
2701
+ * Exposes only booleans — never the trusted key material itself — so frontends
2702
+ * and operators can see whether unsigned plugin installs are rejected and
2703
+ * whether a trusted publisher key has been provisioned.
2704
+ */
2705
+ export type PluginSigningConfig = {
2706
+ /**
2707
+ * Whether a valid signature is required to install a WASM plugin.
2708
+ */
2709
+ required: boolean;
2710
+ /**
2711
+ * Whether an operator trusted public key has been configured. When
2712
+ * `required` is true but this is false, every install is rejected
2713
+ * (fail-closed).
2714
+ */
2715
+ trusted_key_configured: boolean;
2716
+ };
2717
+
2184
2718
  /**
2185
2719
  * Plugin status
2186
2720
  */
@@ -2278,8 +2812,12 @@ export type ProbeBody = {
2278
2812
  export type PromoteArtifactRequest = {
2279
2813
  notes?: string | null;
2280
2814
  skip_policy_check?: boolean;
2281
- target_repository: string;
2282
- };
2815
+ /**
2816
+ * Target release repository key. When omitted, the staging repository's
2817
+ * linked release target (from `repository_config`) is used instead.
2818
+ */
2819
+ target_repository?: string | null;
2820
+ };
2283
2821
 
2284
2822
  export type PromotionHistoryEntry = {
2285
2823
  artifact_id: string;
@@ -2341,6 +2879,50 @@ export type PromotionRuleResponse = {
2341
2879
  updated_at: string;
2342
2880
  };
2343
2881
 
2882
+ /**
2883
+ * Body for declaring that a locally-owned PyPI project tracks an upstream one.
2884
+ */
2885
+ export type PypiTrackRequest = {
2886
+ /**
2887
+ * Upstream Simple index project URL this local project tracks, e.g.
2888
+ * `https://pypi.org/simple/acme-sdk/`. Recorded and emitted as the PEP 708
2889
+ * `tracks` value.
2890
+ */
2891
+ tracks_url: string;
2892
+ };
2893
+
2894
+ /**
2895
+ * A single PEP 708 `tracks` declaration.
2896
+ */
2897
+ export type PypiTrackResponse = {
2898
+ /**
2899
+ * PEP 503 normalized project name.
2900
+ */
2901
+ normalized_name: string;
2902
+ repository_key: string;
2903
+ tracks_url: string;
2904
+ };
2905
+
2906
+ /**
2907
+ * All `tracks` declarations on a repository.
2908
+ */
2909
+ export type PypiTracksListResponse = {
2910
+ items: Array<PypiTrackResponse>;
2911
+ };
2912
+
2913
+ export type QuarantineActionResponse = {
2914
+ artifact_id: string;
2915
+ message: string;
2916
+ new_status: string;
2917
+ };
2918
+
2919
+ export type QuarantineStatusResponse = {
2920
+ artifact_id: string;
2921
+ is_blocked: boolean;
2922
+ quarantine_status?: string | null;
2923
+ quarantine_until?: string | null;
2924
+ };
2925
+
2344
2926
  export type QuickSearchResponse = {
2345
2927
  results: Array<SearchResultItem>;
2346
2928
  };
@@ -2392,6 +2974,13 @@ export type RejectArtifactRequest = {
2392
2974
  reason: string;
2393
2975
  };
2394
2976
 
2977
+ export type RejectRequest = {
2978
+ /**
2979
+ * Optional reason for rejection.
2980
+ */
2981
+ reason?: string | null;
2982
+ };
2983
+
2395
2984
  export type RejectionResponse = {
2396
2985
  artifact_id: string;
2397
2986
  reason: string;
@@ -2400,6 +2989,21 @@ export type RejectionResponse = {
2400
2989
  source: string;
2401
2990
  };
2402
2991
 
2992
+ export type ReleaseTargetResponse = {
2993
+ /**
2994
+ * Whether this staging repository has a linked release target.
2995
+ */
2996
+ linked: boolean;
2997
+ /**
2998
+ * The release repository ID, if linked.
2999
+ */
3000
+ release_repository_id?: string | null;
3001
+ /**
3002
+ * The release repository key, if linked.
3003
+ */
3004
+ release_repository_key?: string | null;
3005
+ };
3006
+
2403
3007
  export type RemoteInstanceResponse = {
2404
3008
  created_at: string;
2405
3009
  id: string;
@@ -2436,6 +3040,30 @@ export type RepoSelectorSchema = {
2436
3040
  match_repos?: Array<string>;
2437
3041
  };
2438
3042
 
3043
+ /**
3044
+ * List of tokens configured on a repository.
3045
+ */
3046
+ export type RepoTokenListResponse = {
3047
+ items: Array<RepoTokenResponse>;
3048
+ };
3049
+
3050
+ /**
3051
+ * Summary of a repository-scoped token.
3052
+ */
3053
+ export type RepoTokenResponse = {
3054
+ created_at: string;
3055
+ created_by?: string | null;
3056
+ description?: string | null;
3057
+ expires_at?: string | null;
3058
+ id: string;
3059
+ is_expired: boolean;
3060
+ is_revoked: boolean;
3061
+ last_used_at?: string | null;
3062
+ name: string;
3063
+ scopes: Array<string>;
3064
+ token_prefix: string;
3065
+ };
3066
+
2439
3067
  export type RepositoryAssessment = {
2440
3068
  artifact_count: number;
2441
3069
  compatibility: string;
@@ -2452,6 +3080,12 @@ export type RepositoryListResponse = {
2452
3080
  };
2453
3081
 
2454
3082
  export type RepositoryResponse = {
3083
+ /**
3084
+ * Whether anonymous (unauthenticated) downloads are allowed. This is
3085
+ * always equal to `is_public` and provided as a convenience alias so
3086
+ * the semantics are clear for remote (pull-through cache) repositories.
3087
+ */
3088
+ allow_anonymous_access: boolean;
2455
3089
  created_at: string;
2456
3090
  description?: string | null;
2457
3091
  format: string;
@@ -2459,6 +3093,21 @@ export type RepositoryResponse = {
2459
3093
  is_public: boolean;
2460
3094
  key: string;
2461
3095
  name: string;
3096
+ /**
3097
+ * When true, direct user uploads are rejected; artifacts must be promoted.
3098
+ */
3099
+ promotion_only: boolean;
3100
+ /**
3101
+ * Configured quarantine hold duration in minutes, read back from
3102
+ * `repository_config` (#1770 B). `None` when unset.
3103
+ */
3104
+ quarantine_duration_minutes?: number | null;
3105
+ /**
3106
+ * Whether the Package Age / quarantine policy is enabled for this
3107
+ * repository, read back from `repository_config` (#1770 B). `None` when
3108
+ * the repository has no explicit setting (the global default applies).
3109
+ */
3110
+ quarantine_enabled?: boolean | null;
2462
3111
  quota_bytes?: number | null;
2463
3112
  repo_type: string;
2464
3113
  storage_used_bytes: number;
@@ -2509,6 +3158,30 @@ export type RepositoryStorageBreakdown = {
2509
3158
  storage_bytes: number;
2510
3159
  };
2511
3160
 
3161
+ export type RescanForInventoryRequest = {
3162
+ /**
3163
+ * Maximum number of artifacts to enqueue in this call. Operators
3164
+ * run the endpoint repeatedly to drain large backfills without
3165
+ * stalling a single HTTP worker; the handler returns the actual
3166
+ * number enqueued so the caller can detect when work is done.
3167
+ * Defaults to 100. Hard-capped at 1000 to avoid pathological inputs.
3168
+ */
3169
+ limit?: number | null;
3170
+ };
3171
+
3172
+ export type RescanForInventoryResponse = {
3173
+ /**
3174
+ * Number of artifacts whose latest scan had no inventory rows and
3175
+ * for which a rescan was enqueued in this call.
3176
+ */
3177
+ artifacts_enqueued: number;
3178
+ /**
3179
+ * Echo of the requested (or defaulted) limit, useful for clients
3180
+ * driving the loop programmatically.
3181
+ */
3182
+ limit: number;
3183
+ };
3184
+
2512
3185
  /**
2513
3186
  * Response for password reset
2514
3187
  */
@@ -2533,6 +3206,12 @@ export type ReviewRequest = {
2533
3206
  * Optional reviewer notes
2534
3207
  */
2535
3208
  notes?: string | null;
3209
+ /**
3210
+ * Admin break-glass override: skip promotion_rules enforcement at approve
3211
+ * time. Mirrors `skip_policy_check` on the single/bulk promote endpoints so
3212
+ * the approval-execute path has the same documented escape hatch.
3213
+ */
3214
+ skip_policy_check?: boolean;
2536
3215
  };
2537
3216
 
2538
3217
  export type RoleListResponse = {
@@ -2546,6 +3225,43 @@ export type RoleResponse = {
2546
3225
  permissions: Array<string>;
2547
3226
  };
2548
3227
 
3228
+ /**
3229
+ * Response returned by the rotate-secret endpoint.
3230
+ */
3231
+ export type RotateWebhookSecretResponse = {
3232
+ id: string;
3233
+ /**
3234
+ * When the previously active secret stops being accepted.
3235
+ */
3236
+ previous_secret_expires_at: string;
3237
+ /**
3238
+ * Raw signing secret produced by this rotation. Shown exactly once.
3239
+ */
3240
+ secret: string;
3241
+ secret_digest: string;
3242
+ };
3243
+
3244
+ /**
3245
+ * A single routing rule that maps an incoming path to a rewritten path.
3246
+ */
3247
+ export type RoutingRule = {
3248
+ /**
3249
+ * Regex pattern matched against the full request path.
3250
+ * Use capture groups to extract portions for the rewrite template.
3251
+ */
3252
+ path_pattern: string;
3253
+ /**
3254
+ * Rewrite template. Use `$1`, `$2`, etc. to reference captured groups
3255
+ * from `path_pattern`.
3256
+ */
3257
+ rewrite_to: string;
3258
+ };
3259
+
3260
+ export type RoutingRulesResponse = {
3261
+ repository_key: string;
3262
+ rules: Array<RoutingRule>;
3263
+ };
3264
+
2549
3265
  export type RuleEvaluationResponse = {
2550
3266
  passed: boolean;
2551
3267
  rule_id: string;
@@ -2568,6 +3284,14 @@ export type RuleResponse = {
2568
3284
  version_constraint: string;
2569
3285
  };
2570
3286
 
3287
+ /**
3288
+ * Result of `POST /:id/repositories/:repo_id/sync` (run-now trigger).
3289
+ */
3290
+ export type RunNowResponse = {
3291
+ status: string;
3292
+ tasks_queued: number;
3293
+ };
3294
+
2571
3295
  export type SamlAcsForm = {
2572
3296
  RelayState?: string | null;
2573
3297
  SAMLResponse: string;
@@ -2646,15 +3370,47 @@ export type ScanResponse = {
2646
3370
  high_count: number;
2647
3371
  id: string;
2648
3372
  info_count: number;
3373
+ /**
3374
+ * True when the row was synthesized by the dedup path (`copy_scan_results`)
3375
+ * because a prior scan with the same `(checksum_sha256, scan_type)` pair
3376
+ * already existed within the dedup TTL. No scanner was actually invoked
3377
+ * for this row; counts and findings were copied from `source_scan_id`.
3378
+ */
3379
+ is_reused: boolean;
2649
3380
  low_count: number;
2650
3381
  medium_count: number;
2651
3382
  repository_id: string;
2652
3383
  scan_type: string;
2653
3384
  scanner_version?: string | null;
3385
+ /**
3386
+ * When `is_reused` is true, the `id` of the source scan whose results
3387
+ * were copied. Useful for distinguishing "fresh scan" from "deduped
3388
+ * satisfaction" in release-gate provenance checks. None for original
3389
+ * (non-reused) scans.
3390
+ */
3391
+ source_scan_id?: string | null;
2654
3392
  started_at?: string | null;
2655
3393
  status: string;
2656
3394
  };
2657
3395
 
3396
+ /**
3397
+ * Scanner availability flags.
3398
+ */
3399
+ export type ScannersConfig = {
3400
+ /**
3401
+ * Whether the Dependency-Track integration is configured.
3402
+ */
3403
+ dependency_track_enabled: boolean;
3404
+ /**
3405
+ * Whether the OpenSCAP compliance scanner is configured.
3406
+ */
3407
+ openscap_enabled: boolean;
3408
+ /**
3409
+ * Whether the Trivy vulnerability scanner is configured.
3410
+ */
3411
+ trivy_enabled: boolean;
3412
+ };
3413
+
2658
3414
  export type ScoreResponse = {
2659
3415
  acknowledged_count: number;
2660
3416
  calculated_at: string;
@@ -2759,6 +3515,22 @@ export type SetPeerLabelsRequest = {
2759
3515
  labels: Array<PeerLabelEntrySchema>;
2760
3516
  };
2761
3517
 
3518
+ export type SetReleaseTargetRequest = {
3519
+ /**
3520
+ * Repository key of the release (local) repository to link.
3521
+ * Pass `null` or omit to remove the link.
3522
+ */
3523
+ release_repository_key?: string | null;
3524
+ };
3525
+
3526
+ export type SetRoutingRulesRequest = {
3527
+ /**
3528
+ * Ordered list of routing rules. Each rule specifies a regex pattern and
3529
+ * a rewrite template. Rules are evaluated in order during proxy requests.
3530
+ */
3531
+ rules: Array<RoutingRule>;
3532
+ };
3533
+
2762
3534
  /**
2763
3535
  * Response body for the setup status endpoint.
2764
3536
  */
@@ -2798,6 +3570,33 @@ export type SigningKeyPublic = {
2798
3570
  uid_name?: string | null;
2799
3571
  };
2800
3572
 
3573
+ /**
3574
+ * Request body for the SMTP test endpoint.
3575
+ */
3576
+ export type SmtpTestRequest = {
3577
+ /**
3578
+ * Recipient email address for the test message.
3579
+ *
3580
+ * Accepts `recipient` as an alias for backward compatibility with Web UI
3581
+ * versions <= 1.1.3, which send `{"recipient": "..."}`.
3582
+ */
3583
+ to: string;
3584
+ };
3585
+
3586
+ /**
3587
+ * Response from the SMTP test endpoint.
3588
+ */
3589
+ export type SmtpTestResponse = {
3590
+ /**
3591
+ * Human-readable status message.
3592
+ */
3593
+ message: string;
3594
+ /**
3595
+ * Whether the test email was sent successfully.
3596
+ */
3597
+ success: boolean;
3598
+ };
3599
+
2801
3600
  export type SourceConnectionRow = {
2802
3601
  auth_type: string;
2803
3602
  created_at: string;
@@ -2900,6 +3699,23 @@ export type SubmitResponse = {
2900
3699
  marked_submitted: number;
2901
3700
  };
2902
3701
 
3702
+ /**
3703
+ * Detailed subscription view (mode, schedule, filter) for a single (peer, repo) pair.
3704
+ */
3705
+ export type SubscriptionResponse = {
3706
+ created_at: string;
3707
+ id: string;
3708
+ last_replicated_at?: string | null;
3709
+ peer_instance_id: string;
3710
+ replication_filter: {
3711
+ [key: string]: unknown;
3712
+ };
3713
+ replication_mode?: string | null;
3714
+ replication_schedule?: string | null;
3715
+ repository_id: string;
3716
+ sync_enabled: boolean;
3717
+ };
3718
+
2903
3719
  export type SuggestResponse = {
2904
3720
  suggestions: Array<string>;
2905
3721
  };
@@ -2925,6 +3741,12 @@ export type SyncPolicyResponse = {
2925
3741
  created_at: string;
2926
3742
  description: string;
2927
3743
  enabled: boolean;
3744
+ /**
3745
+ * Convenience glob filter, mirrored from `artifact_filter.include_paths`.
3746
+ * Round-trips the single-pattern shorthand accepted on create
3747
+ * (e.g. `"*.tar.gz"`). Empty when no include pattern is set.
3748
+ */
3749
+ filter: string;
2928
3750
  id: string;
2929
3751
  name: string;
2930
3752
  peer_selector: {
@@ -2942,11 +3764,87 @@ export type SyncPolicyResponse = {
2942
3764
  export type SyncTaskResponse = {
2943
3765
  artifact_id: string;
2944
3766
  artifact_size: number;
3767
+ /**
3768
+ * When the task was enqueued. Lets clients tell a freshly-scheduled task
3769
+ * apart from a stale queue entry (used by the replication-schedule check).
3770
+ * Serialized as whole-second RFC3339 with a `Z` suffix
3771
+ * (e.g. `2026-05-29T12:34:56Z`) so simple ISO8601 parsers can consume it.
3772
+ */
3773
+ created_at: string;
2945
3774
  id: string;
2946
3775
  priority: number;
3776
+ /**
3777
+ * When the worker began transferring, if it has started. Same format as
3778
+ * `created_at`.
3779
+ */
3780
+ started_at?: string | null;
3781
+ /**
3782
+ * Task status (e.g. "pending"). Listing currently returns pending tasks.
3783
+ */
3784
+ status: string;
2947
3785
  storage_key: string;
2948
3786
  };
2949
3787
 
3788
+ /**
3789
+ * Runtime configuration values.
3790
+ *
3791
+ * This response intentionally omits all secrets, credentials, and internal
3792
+ * connection strings.
3793
+ *
3794
+ * Disclosure is tiered (see `get_system_config`):
3795
+ *
3796
+ * * **Public-safe fields** are always present — they only describe UI/client
3797
+ * affordances a caller needs *before* authenticating (upload limit, demo
3798
+ * mode, whether guest access and which login providers are available).
3799
+ * * **Security-posture fields** (`scanners`, `search_engine`,
3800
+ * `storage_backend`, `permissions`, `plugin_signing`) describe the
3801
+ * instance's defensive configuration. They are returned **only to
3802
+ * authenticated admins** and are omitted for anonymous / non-admin callers,
3803
+ * so the deployment's security posture cannot be fingerprinted by an
3804
+ * unauthenticated attacker.
3805
+ */
3806
+ export type SystemConfigResponse = {
3807
+ /**
3808
+ * Authentication provider availability. Needed by the login UI before the
3809
+ * user authenticates, so this is public-safe.
3810
+ */
3811
+ auth: AuthConfig;
3812
+ /**
3813
+ * Whether the instance is running in demo mode (writes blocked).
3814
+ */
3815
+ demo_mode: boolean;
3816
+ /**
3817
+ * Whether anonymous (unauthenticated) access is permitted at all (issue #850).
3818
+ * When `false`, the server rejects all unauthenticated requests except for
3819
+ * the login, setup, health, and OCI challenge endpoints. Frontends should
3820
+ * hide UI affordances that imply public access (e.g. the "public repo"
3821
+ * toggle) and redirect unauthenticated users to the login page.
3822
+ */
3823
+ guest_access_enabled: boolean;
3824
+ /**
3825
+ * Maximum upload size in bytes (0 means no limit).
3826
+ */
3827
+ max_upload_size_bytes: number;
3828
+ /**
3829
+ * OIDC issuer URL, if configured. This is public information needed by
3830
+ * clients to initiate the OIDC flow.
3831
+ */
3832
+ oidc_issuer?: string | null;
3833
+ permissions?: null | PermissionsConfig;
3834
+ plugin_signing?: null | PluginSigningConfig;
3835
+ scanners?: null | ScannersConfig;
3836
+ /**
3837
+ * Search engine type: "opensearch" when configured, "database" otherwise.
3838
+ * Admin-only (security posture).
3839
+ */
3840
+ search_engine?: string | null;
3841
+ /**
3842
+ * Storage backend type (e.g. "filesystem", "s3", "gcs", "azure").
3843
+ * Admin-only (security posture).
3844
+ */
3845
+ storage_backend?: string | null;
3846
+ };
3847
+
2950
3848
  export type SystemSettings = {
2951
3849
  allow_anonymous_download: boolean;
2952
3850
  audit_retention_days: number;
@@ -3134,12 +4032,45 @@ export type TriggerChecksResponse = {
3134
4032
 
3135
4033
  export type TriggerScanRequest = {
3136
4034
  artifact_id?: string | null;
4035
+ /**
4036
+ * Skip the hash-based scan dedup short-circuit when running this scan.
4037
+ *
4038
+ * Defaults to `false`. Normal trigger calls dedup against prior
4039
+ * completed scans for the same checksum + scan_type so a freshly
4040
+ * uploaded byte-identical artifact reuses the existing result instead
4041
+ * of re-running the scanner. When `true`, that dedup is skipped: the
4042
+ * scanner runs against the bytes again and writes a fresh
4043
+ * `scan_results` row. Use this to recover from a silently-broken
4044
+ * prior scan (e.g. an extraction bug producing a completed,
4045
+ * zero-finding row that masks the real findings until the dedup TTL
4046
+ * expires; see #1469). Costs an extra scan run, so leave it unset
4047
+ * for routine trigger calls.
4048
+ *
4049
+ * **Admin only.** Setting this to `true` bypasses the dedup short-
4050
+ * circuit and fans out unbounded scanner work per artifact. The
4051
+ * `trigger_scan` handler rejects this field with 403 for non-admin
4052
+ * callers, since a non-admin force-rescan path would be a DoS
4053
+ * amplifier (the pre-existing `force=true` was naturally rate-limited
4054
+ * by dedup; `bypass_dedup` removes that safety).
4055
+ */
4056
+ bypass_dedup?: boolean | null;
3137
4057
  repository_id?: string | null;
3138
4058
  };
3139
4059
 
3140
4060
  export type TriggerScanResponse = {
3141
4061
  artifacts_queued: number;
3142
4062
  message: string;
4063
+ /**
4064
+ * Scan result IDs created (one per active scanner) when triggering an
4065
+ * artifact-level scan. Empty for repository-level scans (where the
4066
+ * per-artifact rows are created inside the spawned worker) and for
4067
+ * artifact-level triggers when no scanners are configured.
4068
+ *
4069
+ * Clients (and the release-gate test in artifact-keeper-test#58) should
4070
+ * poll `GET /api/v1/security/scans/{id}` against these IDs rather than
4071
+ * guessing the most-recent scan from `GET /artifacts/{id}/scans`.
4072
+ */
4073
+ scan_result_ids?: Array<string>;
3143
4074
  };
3144
4075
 
3145
4076
  /**
@@ -3211,15 +4142,29 @@ export type UpdateLdapConfigRequest = {
3211
4142
  };
3212
4143
 
3213
4144
  export type UpdateOidcConfigRequest = {
4145
+ /**
4146
+ * Partial update for `attribute_mapping`. Keys present in this object
4147
+ * overwrite the matching keys in the stored mapping. Keys not present
4148
+ * are preserved. To remove a key, set it to `null`. To replace the
4149
+ * whole mapping atomically, set `attribute_mapping_replace = true`.
4150
+ * (See issue #1191.)
4151
+ */
3214
4152
  attribute_mapping?: {
3215
4153
  [key: string]: unknown;
3216
4154
  } | null;
4155
+ /**
4156
+ * When `true`, treat `attribute_mapping` as a wholesale replacement
4157
+ * (legacy behavior). Defaults to `false` — partial merge.
4158
+ */
4159
+ attribute_mapping_replace?: boolean | null;
3217
4160
  auto_create_users?: boolean | null;
3218
4161
  client_id?: string | null;
3219
4162
  client_secret?: string | null;
3220
4163
  is_enabled?: boolean | null;
3221
4164
  issuer_url?: string | null;
4165
+ map_groups_to_groups?: boolean | null;
3222
4166
  name?: string | null;
4167
+ pkce_enabled?: boolean | null;
3223
4168
  scopes?: Array<string> | null;
3224
4169
  };
3225
4170
 
@@ -3229,18 +4174,45 @@ export type UpdatePluginConfigRequest = {
3229
4174
  };
3230
4175
  };
3231
4176
 
4177
+ /**
4178
+ * Partial-update payload for `PUT /security/policies/{id}`.
4179
+ *
4180
+ * Every field is `Option<T>` so clients can send any subset of mutable
4181
+ * columns; omitted fields leave the existing row value untouched. The
4182
+ * previous shape required all of `name`, `max_severity`, `block_unscanned`,
4183
+ * `block_on_fail`, `is_enabled` on every call. That was incompatible with
4184
+ * the release-gate `scan-policy-crud` test (and external callers) which
4185
+ * PATCH a subset like `{max_severity, is_enabled}`; under the strict shape
4186
+ * the request was rejected as a 422 and the boolean toggle silently never
4187
+ * took effect on a follow-up GET. See #1374.
4188
+ *
4189
+ * For `min_staging_hours` / `max_artifact_age_days` the field is the inner
4190
+ * nullable `i32`; "not provided" leaves the column untouched. Explicit
4191
+ * `null` to clear those columns is not currently supported; the release
4192
+ * gate only mutates the bool/enum fields, so the narrower semantics are
4193
+ * sufficient and we avoid an ambiguous JSON contract.
4194
+ */
3232
4195
  export type UpdatePolicyRequest = {
3233
- block_on_fail: boolean;
3234
- block_unscanned: boolean;
3235
- is_enabled: boolean;
4196
+ block_on_fail?: boolean | null;
4197
+ block_unscanned?: boolean | null;
4198
+ is_enabled?: boolean | null;
3236
4199
  max_artifact_age_days?: number | null;
3237
- max_severity: string;
4200
+ max_severity?: string | null;
3238
4201
  min_staging_hours?: number | null;
3239
- name: string;
3240
- require_signature?: boolean;
4202
+ name?: string | null;
4203
+ require_signature?: boolean | null;
3241
4204
  };
3242
4205
 
3243
4206
  export type UpdateRepositoryRequest = {
4207
+ /**
4208
+ * Alias for `is_public`. When set to true, anonymous users can download
4209
+ * artifacts without authentication. Useful for remote (pull-through cache)
4210
+ * repositories that proxy public upstream registries. Write operations
4211
+ * (upload, delete) still require authentication regardless of this setting.
4212
+ * If both `is_public` and `allow_anonymous_access` are provided,
4213
+ * `allow_anonymous_access` takes precedence.
4214
+ */
4215
+ allow_anonymous_access?: boolean | null;
3244
4216
  description?: string | null;
3245
4217
  /**
3246
4218
  * Update the Cargo index upstream URL (stored in `repository_config`).
@@ -3250,7 +4222,31 @@ export type UpdateRepositoryRequest = {
3250
4222
  is_public?: boolean | null;
3251
4223
  key?: string | null;
3252
4224
  name?: string | null;
4225
+ /**
4226
+ * When provided, enables/disables the `promotion_only` policy for this
4227
+ * repository (admin-only). When omitted, the flag is left unchanged.
4228
+ */
4229
+ promotion_only?: boolean | null;
4230
+ /**
4231
+ * Quarantine hold duration in minutes for this repository.
4232
+ * Stored in `repository_config` under `quarantine_duration_minutes`.
4233
+ */
4234
+ quarantine_duration_minutes?: number | null;
4235
+ /**
4236
+ * Enable or disable quarantine period for this repository.
4237
+ * When enabled, newly uploaded artifacts are held until scanned.
4238
+ * Stored in `repository_config` under `quarantine_enabled`.
4239
+ */
4240
+ quarantine_enabled?: boolean | null;
3253
4241
  quota_bytes?: number | null;
4242
+ /**
4243
+ * Link this staging repository to a release (local) repository.
4244
+ * Promotions from this staging repo will default to the linked release repo,
4245
+ * and promotions to any other repo will be rejected.
4246
+ * Pass an empty string to remove the link.
4247
+ * Stored in `repository_config` under `release_repository_id`.
4248
+ */
4249
+ release_repository_key?: string | null;
3254
4250
  };
3255
4251
 
3256
4252
  export type UpdateRuleRequest = {
@@ -3336,13 +4332,25 @@ export type UpsertLicensePolicyRequest = {
3336
4332
 
3337
4333
  /**
3338
4334
  * Request to create or update a scan configuration.
4335
+ *
4336
+ * Every field is optional so a `PUT /repositories/{key}/security` can carry
4337
+ * any subset of mutable columns; fields the client omits keep their existing
4338
+ * value (or fall back to the documented default when the row does not exist
4339
+ * yet). The previous shape required all of `scan_enabled`, `scan_on_upload`,
4340
+ * `scan_on_proxy`, `block_on_policy_violation`, `severity_threshold` on every
4341
+ * call. That was the #1374 bug class on a second entity: a partial PUT (for
4342
+ * example just `{scan_enabled: true}`) either bounced as a 422 or, worse,
4343
+ * silently reset every other column to its default so a follow-up GET showed
4344
+ * the untouched fields stale. The upsert is now a read-modify-write that
4345
+ * merges the patch over the existing row, so multiple fields persist together
4346
+ * and an omitted field is never clobbered. See #1374 / B11.
3339
4347
  */
3340
4348
  export type UpsertScanConfigRequest = {
3341
- block_on_policy_violation: boolean;
3342
- scan_enabled: boolean;
3343
- scan_on_proxy: boolean;
3344
- scan_on_upload: boolean;
3345
- severity_threshold: string;
4349
+ block_on_policy_violation?: boolean | null;
4350
+ scan_enabled?: boolean | null;
4351
+ scan_on_proxy?: boolean | null;
4352
+ scan_on_upload?: boolean | null;
4353
+ severity_threshold?: string | null;
3346
4354
  };
3347
4355
 
3348
4356
  export type UpstreamAuthRequest = {
@@ -3433,6 +4441,12 @@ export type WebhookListResponse = {
3433
4441
 
3434
4442
  export type WebhookResponse = {
3435
4443
  created_at: string;
4444
+ /**
4445
+ * Pinned event payload version (e.g. "2026-04-01"). Determines the
4446
+ * shape of the rendered payload and the value sent in the
4447
+ * `X-ArtifactKeeper-Event-Version` header.
4448
+ */
4449
+ event_schema_version: string;
3436
4450
  events: Array<string>;
3437
4451
  headers?: {
3438
4452
  [key: string]: unknown;
@@ -3441,10 +4455,42 @@ export type WebhookResponse = {
3441
4455
  is_enabled: boolean;
3442
4456
  last_triggered_at?: string | null;
3443
4457
  name: string;
4458
+ payload_template: PayloadTemplate;
3444
4459
  repository_id?: string | null;
4460
+ /**
4461
+ * Short non-reversible identifier for the current signing secret
4462
+ * (`whsec_...abcd`), suitable for display in operator UIs. The raw
4463
+ * secret is never returned by GET or LIST.
4464
+ */
4465
+ secret_digest?: string | null;
4466
+ /**
4467
+ * True while a previous secret is still accepted by the retry path
4468
+ * during a rotation overlap window.
4469
+ */
4470
+ secret_rotation_active?: boolean;
3445
4471
  url: string;
3446
4472
  };
3447
4473
 
4474
+ /**
4475
+ * Response returned exactly once when a webhook is created or its secret
4476
+ * is rotated. The raw `secret` value is not retrievable afterwards.
4477
+ */
4478
+ export type WebhookSecretCreatedResponse = WebhookResponse & {
4479
+ /**
4480
+ * Raw signing secret. Display this to the operator immediately and
4481
+ * instruct them to record it; the server retains only the encrypted
4482
+ * form and a short digest.
4483
+ *
4484
+ * Absent when the webhook was created without a signing secret. This
4485
+ * happens when no secret was supplied and the deployment has no
4486
+ * `AK_WEBHOOK_SECRET_KEY` configured: rather than fail the create with
4487
+ * a 500, the webhook is stored unsigned and deliveries omit the
4488
+ * signature header. Configure the key and rotate the secret later to
4489
+ * enable signing.
4490
+ */
4491
+ secret?: string | null;
4492
+ };
4493
+
3448
4494
  export type GetStaleArtifactsData = {
3449
4495
  body?: never;
3450
4496
  path?: never;
@@ -3707,6 +4753,10 @@ export type CancelBackupErrors = {
3707
4753
  * Backup not found
3708
4754
  */
3709
4755
  404: unknown;
4756
+ /**
4757
+ * Backup is not in a cancellable state
4758
+ */
4759
+ 409: unknown;
3710
4760
  /**
3711
4761
  * Internal server error
3712
4762
  */
@@ -4066,23 +5116,53 @@ export type TriggerReindexResponses = {
4066
5116
 
4067
5117
  export type TriggerReindexResponse = TriggerReindexResponses[keyof TriggerReindexResponses];
4068
5118
 
4069
- export type TriggerSearchReindexData = {
4070
- body?: never;
5119
+ export type RescanForInventoryData = {
5120
+ /**
5121
+ * Optional; empty body uses defaults
5122
+ */
5123
+ body: RescanForInventoryRequest;
4071
5124
  path?: never;
4072
5125
  query?: never;
4073
- url: '/api/v1/admin/search/reindex';
5126
+ url: '/api/v1/admin/rescan-for-inventory';
4074
5127
  };
4075
5128
 
4076
- export type TriggerSearchReindexErrors = {
5129
+ export type RescanForInventoryErrors = {
4077
5130
  /**
4078
- * Meilisearch is not configured
5131
+ * Admin privileges required
4079
5132
  */
4080
- 500: unknown;
5133
+ 403: unknown;
5134
+ /**
5135
+ * Scanner service not configured
5136
+ */
5137
+ 503: unknown;
4081
5138
  };
4082
5139
 
4083
- export type TriggerSearchReindexResponses = {
5140
+ export type RescanForInventoryResponses = {
4084
5141
  /**
4085
- * Reindex started in background
5142
+ * Rescans enqueued
5143
+ */
5144
+ 200: RescanForInventoryResponse;
5145
+ };
5146
+
5147
+ export type RescanForInventoryResponse2 = RescanForInventoryResponses[keyof RescanForInventoryResponses];
5148
+
5149
+ export type TriggerSearchReindexData = {
5150
+ body?: never;
5151
+ path?: never;
5152
+ query?: never;
5153
+ url: '/api/v1/admin/search/reindex';
5154
+ };
5155
+
5156
+ export type TriggerSearchReindexErrors = {
5157
+ /**
5158
+ * Search engine is not configured
5159
+ */
5160
+ 500: unknown;
5161
+ };
5162
+
5163
+ export type TriggerSearchReindexResponses = {
5164
+ /**
5165
+ * Reindex started in background
4086
5166
  */
4087
5167
  200: ReindexResponse;
4088
5168
  };
@@ -4135,6 +5215,37 @@ export type UpdateSettingsResponses = {
4135
5215
 
4136
5216
  export type UpdateSettingsResponse = UpdateSettingsResponses[keyof UpdateSettingsResponses];
4137
5217
 
5218
+ export type SendTestEmailData = {
5219
+ body: SmtpTestRequest;
5220
+ path?: never;
5221
+ query?: never;
5222
+ url: '/api/v1/admin/smtp/test';
5223
+ };
5224
+
5225
+ export type SendTestEmailErrors = {
5226
+ /**
5227
+ * Invalid request (e.g. bad email address)
5228
+ */
5229
+ 400: unknown;
5230
+ /**
5231
+ * Admin privileges required
5232
+ */
5233
+ 403: unknown;
5234
+ /**
5235
+ * SMTP not configured
5236
+ */
5237
+ 503: unknown;
5238
+ };
5239
+
5240
+ export type SendTestEmailResponses = {
5241
+ /**
5242
+ * Test email sent successfully
5243
+ */
5244
+ 200: SmtpTestResponse;
5245
+ };
5246
+
5247
+ export type SendTestEmailResponse = SendTestEmailResponses[keyof SendTestEmailResponses];
5248
+
4138
5249
  export type ListLdapData = {
4139
5250
  body?: never;
4140
5251
  path?: never;
@@ -4802,6 +5913,28 @@ export type RunStorageGcResponses = {
4802
5913
 
4803
5914
  export type RunStorageGcResponse = RunStorageGcResponses[keyof RunStorageGcResponses];
4804
5915
 
5916
+ export type OciBlobReportData = {
5917
+ body?: never;
5918
+ path?: never;
5919
+ query?: {
5920
+ /**
5921
+ * Grace window in hours used to compute the `aged_*` figures. Defaults
5922
+ * to 24h; non-positive or out-of-range values are clamped server-side.
5923
+ */
5924
+ grace_hours?: number | null;
5925
+ };
5926
+ url: '/api/v1/admin/storage-gc/oci-blob-report';
5927
+ };
5928
+
5929
+ export type OciBlobReportResponses = {
5930
+ /**
5931
+ * OCI blob footprint report
5932
+ */
5933
+ 200: OciBlobFootprintReport;
5934
+ };
5935
+
5936
+ export type OciBlobReportResponse = OciBlobReportResponses[keyof OciBlobReportResponses];
5937
+
4805
5938
  export type ListCrashesData = {
4806
5939
  body?: never;
4807
5940
  path?: never;
@@ -5362,7 +6495,7 @@ export type LoginResponses = {
5362
6495
  export type LoginResponse2 = LoginResponses[keyof LoginResponses];
5363
6496
 
5364
6497
  export type LogoutData = {
5365
- body?: never;
6498
+ body?: RefreshTokenRequest;
5366
6499
  path?: never;
5367
6500
  query?: never;
5368
6501
  url: '/api/v1/auth/logout';
@@ -5494,9 +6627,12 @@ export type OidcCallbackData = {
5494
6627
  */
5495
6628
  id: string;
5496
6629
  };
5497
- query: {
5498
- code: string;
5499
- state: string;
6630
+ query?: {
6631
+ code?: string | null;
6632
+ state?: string | null;
6633
+ error?: string | null;
6634
+ error_description?: string | null;
6635
+ error_uri?: string | null;
5500
6636
  };
5501
6637
  url: '/api/v1/auth/sso/oidc/{id}/callback';
5502
6638
  };
@@ -5506,6 +6642,10 @@ export type OidcCallbackErrors = {
5506
6642
  * Invalid callback parameters
5507
6643
  */
5508
6644
  400: ErrorResponse;
6645
+ /**
6646
+ * IdP error or invalid/expired SSO state
6647
+ */
6648
+ 401: ErrorResponse;
5509
6649
  };
5510
6650
 
5511
6651
  export type OidcCallbackError = OidcCallbackErrors[keyof OidcCallbackErrors];
@@ -6453,6 +7593,10 @@ export type ListGroupsData = {
6453
7593
  };
6454
7594
 
6455
7595
  export type ListGroupsErrors = {
7596
+ /**
7597
+ * Authentication required
7598
+ */
7599
+ 401: unknown;
6456
7600
  /**
6457
7601
  * Internal server error
6458
7602
  */
@@ -6476,6 +7620,14 @@ export type CreateGroupData = {
6476
7620
  };
6477
7621
 
6478
7622
  export type CreateGroupErrors = {
7623
+ /**
7624
+ * Authentication required
7625
+ */
7626
+ 401: unknown;
7627
+ /**
7628
+ * Insufficient permissions
7629
+ */
7630
+ 403: unknown;
6479
7631
  /**
6480
7632
  * Group name already exists
6481
7633
  */
@@ -6508,6 +7660,14 @@ export type DeleteGroupData = {
6508
7660
  };
6509
7661
 
6510
7662
  export type DeleteGroupErrors = {
7663
+ /**
7664
+ * Authentication required
7665
+ */
7666
+ 401: unknown;
7667
+ /**
7668
+ * Insufficient permissions
7669
+ */
7670
+ 403: unknown;
6511
7671
  /**
6512
7672
  * Group not found
6513
7673
  */
@@ -6547,6 +7707,10 @@ export type GetGroupData = {
6547
7707
  };
6548
7708
 
6549
7709
  export type GetGroupErrors = {
7710
+ /**
7711
+ * Authentication required
7712
+ */
7713
+ 401: unknown;
6550
7714
  /**
6551
7715
  * Group not found
6552
7716
  */
@@ -6579,6 +7743,14 @@ export type UpdateGroupData = {
6579
7743
  };
6580
7744
 
6581
7745
  export type UpdateGroupErrors = {
7746
+ /**
7747
+ * Authentication required
7748
+ */
7749
+ 401: unknown;
7750
+ /**
7751
+ * Insufficient permissions
7752
+ */
7753
+ 403: unknown;
6582
7754
  /**
6583
7755
  * Group not found
6584
7756
  */
@@ -6611,6 +7783,14 @@ export type RemoveMembersData = {
6611
7783
  };
6612
7784
 
6613
7785
  export type RemoveMembersErrors = {
7786
+ /**
7787
+ * Authentication required
7788
+ */
7789
+ 401: unknown;
7790
+ /**
7791
+ * Insufficient permissions
7792
+ */
7793
+ 403: unknown;
6614
7794
  /**
6615
7795
  * Group not found
6616
7796
  */
@@ -6641,6 +7821,14 @@ export type AddMembersData = {
6641
7821
  };
6642
7822
 
6643
7823
  export type AddMembersErrors = {
7824
+ /**
7825
+ * Authentication required
7826
+ */
7827
+ 401: unknown;
7828
+ /**
7829
+ * Insufficient permissions
7830
+ */
7831
+ 403: unknown;
6644
7832
  /**
6645
7833
  * Group not found
6646
7834
  */
@@ -6836,6 +8024,14 @@ export type CreateMigrationData = {
6836
8024
  };
6837
8025
 
6838
8026
  export type CreateMigrationErrors = {
8027
+ /**
8028
+ * Invalid request (e.g. unknown job_type)
8029
+ */
8030
+ 400: unknown;
8031
+ /**
8032
+ * Source connection not found
8033
+ */
8034
+ 404: unknown;
6839
8035
  /**
6840
8036
  * Internal server error
6841
8037
  */
@@ -7811,6 +9007,17 @@ export type ProbePeerData = {
7811
9007
  url: '/api/v1/peers/{id}/connections/probe';
7812
9008
  };
7813
9009
 
9010
+ export type ProbePeerErrors = {
9011
+ /**
9012
+ * target_peer_id equals the source peer id
9013
+ */
9014
+ 400: unknown;
9015
+ /**
9016
+ * Source or target peer instance not found
9017
+ */
9018
+ 404: unknown;
9019
+ };
9020
+
7814
9021
  export type ProbePeerResponses = {
7815
9022
  /**
7816
9023
  * Probe result recorded
@@ -7914,6 +9121,10 @@ export type SetLabelsData = {
7914
9121
  };
7915
9122
 
7916
9123
  export type SetLabelsErrors = {
9124
+ /**
9125
+ * Admin access required
9126
+ */
9127
+ 403: unknown;
7917
9128
  /**
7918
9129
  * Peer instance not found
7919
9130
  */
@@ -7946,6 +9157,10 @@ export type DeleteLabelData = {
7946
9157
  };
7947
9158
 
7948
9159
  export type DeleteLabelErrors = {
9160
+ /**
9161
+ * Admin access required
9162
+ */
9163
+ 403: unknown;
7949
9164
  /**
7950
9165
  * Peer instance or label not found
7951
9166
  */
@@ -7978,6 +9193,10 @@ export type AddLabelData = {
7978
9193
  };
7979
9194
 
7980
9195
  export type AddLabelErrors = {
9196
+ /**
9197
+ * Admin access required
9198
+ */
9199
+ 403: unknown;
7981
9200
  /**
7982
9201
  * Peer instance not found
7983
9202
  */
@@ -8058,7 +9277,11 @@ export type AssignRepoData = {
8058
9277
 
8059
9278
  export type AssignRepoErrors = {
8060
9279
  /**
8061
- * Peer instance not found
9280
+ * Invalid replication_mode
9281
+ */
9282
+ 400: unknown;
9283
+ /**
9284
+ * Peer instance or repository not found
8062
9285
  */
8063
9286
  404: unknown;
8064
9287
  /**
@@ -8108,6 +9331,78 @@ export type UnassignRepoResponses = {
8108
9331
  200: unknown;
8109
9332
  };
8110
9333
 
9334
+ export type GetSubscriptionData = {
9335
+ body?: never;
9336
+ path: {
9337
+ /**
9338
+ * Peer instance ID
9339
+ */
9340
+ id: string;
9341
+ /**
9342
+ * Repository ID
9343
+ */
9344
+ repo_id: string;
9345
+ };
9346
+ query?: never;
9347
+ url: '/api/v1/peers/{id}/repositories/{repo_id}';
9348
+ };
9349
+
9350
+ export type GetSubscriptionErrors = {
9351
+ /**
9352
+ * Subscription not found
9353
+ */
9354
+ 404: unknown;
9355
+ /**
9356
+ * Internal server error
9357
+ */
9358
+ 500: unknown;
9359
+ };
9360
+
9361
+ export type GetSubscriptionResponses = {
9362
+ /**
9363
+ * Subscription details
9364
+ */
9365
+ 200: SubscriptionResponse;
9366
+ };
9367
+
9368
+ export type GetSubscriptionResponse = GetSubscriptionResponses[keyof GetSubscriptionResponses];
9369
+
9370
+ export type RunSubscriptionNowData = {
9371
+ body?: never;
9372
+ path: {
9373
+ /**
9374
+ * Peer instance ID
9375
+ */
9376
+ id: string;
9377
+ /**
9378
+ * Repository ID
9379
+ */
9380
+ repo_id: string;
9381
+ };
9382
+ query?: never;
9383
+ url: '/api/v1/peers/{id}/repositories/{repo_id}/sync';
9384
+ };
9385
+
9386
+ export type RunSubscriptionNowErrors = {
9387
+ /**
9388
+ * Subscription not found
9389
+ */
9390
+ 404: unknown;
9391
+ /**
9392
+ * Internal server error
9393
+ */
9394
+ 500: unknown;
9395
+ };
9396
+
9397
+ export type RunSubscriptionNowResponses = {
9398
+ /**
9399
+ * Sync tasks queued
9400
+ */
9401
+ 202: RunNowResponse;
9402
+ };
9403
+
9404
+ export type RunSubscriptionNowResponse = RunSubscriptionNowResponses[keyof RunSubscriptionNowResponses];
9405
+
8111
9406
  export type TriggerSyncData = {
8112
9407
  body?: never;
8113
9408
  path: {
@@ -9177,6 +10472,74 @@ export type PromotionHistoryResponses = {
9177
10472
 
9178
10473
  export type PromotionHistoryResponse2 = PromotionHistoryResponses[keyof PromotionHistoryResponses];
9179
10474
 
10475
+ export type GetReleaseTargetData = {
10476
+ body?: never;
10477
+ path: {
10478
+ /**
10479
+ * Staging repository key
10480
+ */
10481
+ key: string;
10482
+ };
10483
+ query?: never;
10484
+ url: '/api/v1/promotion/repositories/{key}/release-target';
10485
+ };
10486
+
10487
+ export type GetReleaseTargetErrors = {
10488
+ /**
10489
+ * Repository not found
10490
+ */
10491
+ 404: ErrorResponse;
10492
+ /**
10493
+ * Repository is not a staging repository
10494
+ */
10495
+ 422: ErrorResponse;
10496
+ };
10497
+
10498
+ export type GetReleaseTargetError = GetReleaseTargetErrors[keyof GetReleaseTargetErrors];
10499
+
10500
+ export type GetReleaseTargetResponses = {
10501
+ /**
10502
+ * Release target information
10503
+ */
10504
+ 200: ReleaseTargetResponse;
10505
+ };
10506
+
10507
+ export type GetReleaseTargetResponse = GetReleaseTargetResponses[keyof GetReleaseTargetResponses];
10508
+
10509
+ export type SetReleaseTargetData = {
10510
+ body: SetReleaseTargetRequest;
10511
+ path: {
10512
+ /**
10513
+ * Staging repository key
10514
+ */
10515
+ key: string;
10516
+ };
10517
+ query?: never;
10518
+ url: '/api/v1/promotion/repositories/{key}/release-target';
10519
+ };
10520
+
10521
+ export type SetReleaseTargetErrors = {
10522
+ /**
10523
+ * Repository not found
10524
+ */
10525
+ 404: ErrorResponse;
10526
+ /**
10527
+ * Validation error
10528
+ */
10529
+ 422: ErrorResponse;
10530
+ };
10531
+
10532
+ export type SetReleaseTargetError = SetReleaseTargetErrors[keyof SetReleaseTargetErrors];
10533
+
10534
+ export type SetReleaseTargetResponses = {
10535
+ /**
10536
+ * Release target updated
10537
+ */
10538
+ 200: ReleaseTargetResponse;
10539
+ };
10540
+
10541
+ export type SetReleaseTargetResponse = SetReleaseTargetResponses[keyof SetReleaseTargetResponses];
10542
+
9180
10543
  export type ListChecksData = {
9181
10544
  body?: never;
9182
10545
  path?: never;
@@ -9582,22 +10945,134 @@ export type SuppressIssueResponses = {
9582
10945
 
9583
10946
  export type SuppressIssueResponse = SuppressIssueResponses[keyof SuppressIssueResponses];
9584
10947
 
9585
- export type ListRepositoriesData = {
10948
+ export type GetQuarantineStatusData = {
9586
10949
  body?: never;
9587
- path?: never;
9588
- query?: {
9589
- page?: number | null;
9590
- per_page?: number | null;
9591
- format?: string | null;
9592
- type?: string | null;
9593
- q?: string | null;
10950
+ path: {
10951
+ /**
10952
+ * Artifact ID
10953
+ */
10954
+ artifact_id: string;
9594
10955
  };
9595
- url: '/api/v1/repositories';
10956
+ query?: never;
10957
+ url: '/api/v1/quarantine/{artifact_id}';
9596
10958
  };
9597
10959
 
9598
- export type ListRepositoriesResponses = {
10960
+ export type GetQuarantineStatusErrors = {
9599
10961
  /**
9600
- * List of repositories
10962
+ * Authentication required
10963
+ */
10964
+ 401: unknown;
10965
+ /**
10966
+ * Artifact not found
10967
+ */
10968
+ 404: unknown;
10969
+ };
10970
+
10971
+ export type GetQuarantineStatusResponses = {
10972
+ /**
10973
+ * Quarantine status
10974
+ */
10975
+ 200: QuarantineStatusResponse;
10976
+ };
10977
+
10978
+ export type GetQuarantineStatusResponse = GetQuarantineStatusResponses[keyof GetQuarantineStatusResponses];
10979
+
10980
+ export type RejectQuarantinedArtifactData = {
10981
+ body: RejectRequest;
10982
+ path: {
10983
+ /**
10984
+ * Artifact ID
10985
+ */
10986
+ artifact_id: string;
10987
+ };
10988
+ query?: never;
10989
+ url: '/api/v1/quarantine/{artifact_id}/reject';
10990
+ };
10991
+
10992
+ export type RejectQuarantinedArtifactErrors = {
10993
+ /**
10994
+ * Authentication required
10995
+ */
10996
+ 401: unknown;
10997
+ /**
10998
+ * Admin access required
10999
+ */
11000
+ 403: unknown;
11001
+ /**
11002
+ * Artifact not found
11003
+ */
11004
+ 404: unknown;
11005
+ /**
11006
+ * Artifact is not in quarantined state
11007
+ */
11008
+ 409: unknown;
11009
+ };
11010
+
11011
+ export type RejectQuarantinedArtifactResponses = {
11012
+ /**
11013
+ * Artifact rejected
11014
+ */
11015
+ 200: QuarantineActionResponse;
11016
+ };
11017
+
11018
+ export type RejectQuarantinedArtifactResponse = RejectQuarantinedArtifactResponses[keyof RejectQuarantinedArtifactResponses];
11019
+
11020
+ export type ReleaseArtifactData = {
11021
+ body?: never;
11022
+ path: {
11023
+ /**
11024
+ * Artifact ID
11025
+ */
11026
+ artifact_id: string;
11027
+ };
11028
+ query?: never;
11029
+ url: '/api/v1/quarantine/{artifact_id}/release';
11030
+ };
11031
+
11032
+ export type ReleaseArtifactErrors = {
11033
+ /**
11034
+ * Authentication required
11035
+ */
11036
+ 401: unknown;
11037
+ /**
11038
+ * Admin access required
11039
+ */
11040
+ 403: unknown;
11041
+ /**
11042
+ * Artifact not found
11043
+ */
11044
+ 404: unknown;
11045
+ /**
11046
+ * Artifact is not in quarantined state
11047
+ */
11048
+ 409: unknown;
11049
+ };
11050
+
11051
+ export type ReleaseArtifactResponses = {
11052
+ /**
11053
+ * Artifact released
11054
+ */
11055
+ 200: QuarantineActionResponse;
11056
+ };
11057
+
11058
+ export type ReleaseArtifactResponse = ReleaseArtifactResponses[keyof ReleaseArtifactResponses];
11059
+
11060
+ export type ListRepositoriesData = {
11061
+ body?: never;
11062
+ path?: never;
11063
+ query?: {
11064
+ page?: number | null;
11065
+ per_page?: number | null;
11066
+ format?: string | null;
11067
+ type?: string | null;
11068
+ q?: string | null;
11069
+ };
11070
+ url: '/api/v1/repositories';
11071
+ };
11072
+
11073
+ export type ListRepositoriesResponses = {
11074
+ /**
11075
+ * List of repositories
9601
11076
  */
9602
11077
  200: RepositoryListResponse;
9603
11078
  };
@@ -9616,6 +11091,10 @@ export type CreateRepositoryErrors = {
9616
11091
  * Authentication required
9617
11092
  */
9618
11093
  401: unknown;
11094
+ /**
11095
+ * Insufficient permissions
11096
+ */
11097
+ 403: unknown;
9619
11098
  /**
9620
11099
  * Repository key already exists
9621
11100
  */
@@ -9648,6 +11127,10 @@ export type DeleteRepositoryErrors = {
9648
11127
  * Authentication required
9649
11128
  */
9650
11129
  401: unknown;
11130
+ /**
11131
+ * Insufficient permissions
11132
+ */
11133
+ 403: unknown;
9651
11134
  /**
9652
11135
  * Repository not found
9653
11136
  */
@@ -9706,6 +11189,10 @@ export type UpdateRepositoryErrors = {
9706
11189
  * Authentication required
9707
11190
  */
9708
11191
  401: unknown;
11192
+ /**
11193
+ * Insufficient permissions
11194
+ */
11195
+ 403: unknown;
9709
11196
  /**
9710
11197
  * Repository not found
9711
11198
  */
@@ -9738,6 +11225,19 @@ export type ListArtifactsData = {
9738
11225
  per_page?: number | null;
9739
11226
  q?: string | null;
9740
11227
  path_prefix?: string | null;
11228
+ /**
11229
+ * Server-side artifact grouping.
11230
+ *
11231
+ * Supported values:
11232
+ * - `maven_component`: Maven/Gradle artifacts are grouped by
11233
+ * groupId, artifactId, and version. Individual files (jar, pom,
11234
+ * checksums) appear in the `artifact_files` array of each component.
11235
+ * - `docker_tag`: Docker/OCI artifacts are grouped by (image, tag),
11236
+ * with `total_size_bytes` summed across the manifest config and
11237
+ * referenced layer blobs. The grouped rows are returned in the
11238
+ * `docker_tags` array.
11239
+ */
11240
+ group_by?: string | null;
9741
11241
  };
9742
11242
  url: '/api/v1/repositories/{key}/artifacts';
9743
11243
  };
@@ -9783,6 +11283,10 @@ export type DeleteArtifactErrors = {
9783
11283
  * Artifact not found
9784
11284
  */
9785
11285
  404: unknown;
11286
+ /**
11287
+ * Artifact is immutable (released) and cannot be deleted
11288
+ */
11289
+ 409: unknown;
9786
11290
  };
9787
11291
 
9788
11292
  export type DeleteArtifactResponses = {
@@ -9924,6 +11428,55 @@ export type SetCacheTtlResponses = {
9924
11428
 
9925
11429
  export type SetCacheTtlResponse = SetCacheTtlResponses[keyof SetCacheTtlResponses];
9926
11430
 
11431
+ export type InvalidateCacheData = {
11432
+ body?: never;
11433
+ path: {
11434
+ /**
11435
+ * Repository key
11436
+ */
11437
+ key: string;
11438
+ };
11439
+ query: {
11440
+ /**
11441
+ * Artifact path to evict from the proxy cache. Same shape as the path
11442
+ * segment of `GET /api/v1/repositories/{key}/artifacts/{path}`.
11443
+ * Path-traversal segments such as `..` are rejected by
11444
+ * `ProxyService::cache_storage_key` (covered by
11445
+ * `test_invalidate_cache_by_key_rejects_invalid_path`).
11446
+ */
11447
+ path: string;
11448
+ };
11449
+ url: '/api/v1/repositories/{key}/cache/invalidate';
11450
+ };
11451
+
11452
+ export type InvalidateCacheErrors = {
11453
+ /**
11454
+ * Validation error (e.g. non-remote repo or invalid path)
11455
+ */
11456
+ 400: unknown;
11457
+ /**
11458
+ * Authentication required
11459
+ */
11460
+ 401: unknown;
11461
+ /**
11462
+ * Repository not found
11463
+ */
11464
+ 404: unknown;
11465
+ /**
11466
+ * Proxy service not configured on this deployment
11467
+ */
11468
+ 503: unknown;
11469
+ };
11470
+
11471
+ export type InvalidateCacheResponses = {
11472
+ /**
11473
+ * Cache entry invalidated (or was already absent)
11474
+ */
11475
+ 200: InvalidateCacheResponse;
11476
+ };
11477
+
11478
+ export type InvalidateCacheResponse2 = InvalidateCacheResponses[keyof InvalidateCacheResponses];
11479
+
9927
11480
  export type DownloadArtifactData = {
9928
11481
  body?: never;
9929
11482
  path: {
@@ -9956,6 +11509,122 @@ export type DownloadArtifactResponses = {
9956
11509
 
9957
11510
  export type DownloadArtifactResponse = DownloadArtifactResponses[keyof DownloadArtifactResponses];
9958
11511
 
11512
+ export type ListSubscriptionsData = {
11513
+ body?: never;
11514
+ path: {
11515
+ /**
11516
+ * Repository key
11517
+ */
11518
+ key: string;
11519
+ };
11520
+ query?: never;
11521
+ url: '/api/v1/repositories/{key}/email-subscriptions';
11522
+ };
11523
+
11524
+ export type ListSubscriptionsErrors = {
11525
+ /**
11526
+ * Not authenticated
11527
+ */
11528
+ 401: unknown;
11529
+ /**
11530
+ * Insufficient permissions
11531
+ */
11532
+ 403: unknown;
11533
+ /**
11534
+ * Repository not found
11535
+ */
11536
+ 404: unknown;
11537
+ };
11538
+
11539
+ export type ListSubscriptionsResponses = {
11540
+ /**
11541
+ * List of email subscriptions
11542
+ */
11543
+ 200: EmailSubscriptionListResponse;
11544
+ };
11545
+
11546
+ export type ListSubscriptionsResponse = ListSubscriptionsResponses[keyof ListSubscriptionsResponses];
11547
+
11548
+ export type CreateSubscriptionData = {
11549
+ body: CreateEmailSubscriptionRequest;
11550
+ path: {
11551
+ /**
11552
+ * Repository key
11553
+ */
11554
+ key: string;
11555
+ };
11556
+ query?: never;
11557
+ url: '/api/v1/repositories/{key}/email-subscriptions';
11558
+ };
11559
+
11560
+ export type CreateSubscriptionErrors = {
11561
+ /**
11562
+ * Validation error
11563
+ */
11564
+ 400: unknown;
11565
+ /**
11566
+ * Not authenticated
11567
+ */
11568
+ 401: unknown;
11569
+ /**
11570
+ * Insufficient permissions
11571
+ */
11572
+ 403: unknown;
11573
+ /**
11574
+ * Repository not found
11575
+ */
11576
+ 404: unknown;
11577
+ };
11578
+
11579
+ export type CreateSubscriptionResponses = {
11580
+ /**
11581
+ * Subscription created
11582
+ */
11583
+ 201: EmailSubscriptionResponse;
11584
+ };
11585
+
11586
+ export type CreateSubscriptionResponse = CreateSubscriptionResponses[keyof CreateSubscriptionResponses];
11587
+
11588
+ export type DeleteSubscriptionData = {
11589
+ body?: never;
11590
+ path: {
11591
+ /**
11592
+ * Repository key
11593
+ */
11594
+ key: string;
11595
+ /**
11596
+ * Subscription ID
11597
+ */
11598
+ subscription_id: string;
11599
+ };
11600
+ query?: never;
11601
+ url: '/api/v1/repositories/{key}/email-subscriptions/{subscription_id}';
11602
+ };
11603
+
11604
+ export type DeleteSubscriptionErrors = {
11605
+ /**
11606
+ * Not authenticated
11607
+ */
11608
+ 401: unknown;
11609
+ /**
11610
+ * Insufficient permissions
11611
+ */
11612
+ 403: unknown;
11613
+ /**
11614
+ * Subscription or repository not found
11615
+ */
11616
+ 404: unknown;
11617
+ };
11618
+
11619
+ export type DeleteSubscriptionResponses = {
11620
+ /**
11621
+ * Subscription deleted
11622
+ */
11623
+ 204: void;
11624
+ };
11625
+
11626
+ export type DeleteSubscriptionResponse = DeleteSubscriptionResponses[keyof DeleteSubscriptionResponses];
11627
+
9959
11628
  export type ListRepoLabelsData = {
9960
11629
  body?: never;
9961
11630
  path: {
@@ -10093,6 +11762,10 @@ export type ListVirtualMembersErrors = {
10093
11762
  * Repository is not virtual
10094
11763
  */
10095
11764
  400: unknown;
11765
+ /**
11766
+ * Authentication required
11767
+ */
11768
+ 401: unknown;
10096
11769
  /**
10097
11770
  * Repository not found
10098
11771
  */
@@ -10101,7 +11774,7 @@ export type ListVirtualMembersErrors = {
10101
11774
 
10102
11775
  export type ListVirtualMembersResponses = {
10103
11776
  /**
10104
- * List of virtual repository members
11777
+ * List of virtual repository members (filtered to caller-visible members)
10105
11778
  */
10106
11779
  200: VirtualMembersListResponse;
10107
11780
  };
@@ -10129,6 +11802,10 @@ export type AddVirtualMemberErrors = {
10129
11802
  * Repository or member not found
10130
11803
  */
10131
11804
  404: unknown;
11805
+ /**
11806
+ * Member already exists in virtual repository
11807
+ */
11808
+ 409: unknown;
10132
11809
  };
10133
11810
 
10134
11811
  export type AddVirtualMemberResponses = {
@@ -10214,7 +11891,7 @@ export type RemoveVirtualMemberResponses = {
10214
11891
  200: unknown;
10215
11892
  };
10216
11893
 
10217
- export type GetRepoSecurityData = {
11894
+ export type ListPypiTracksData = {
10218
11895
  body?: never;
10219
11896
  path: {
10220
11897
  /**
@@ -10223,131 +11900,485 @@ export type GetRepoSecurityData = {
10223
11900
  key: string;
10224
11901
  };
10225
11902
  query?: never;
10226
- url: '/api/v1/repositories/{key}/security';
11903
+ url: '/api/v1/repositories/{key}/pypi-tracks';
10227
11904
  };
10228
11905
 
10229
- export type GetRepoSecurityErrors = {
11906
+ export type ListPypiTracksErrors = {
10230
11907
  /**
10231
11908
  * Repository not found
10232
11909
  */
10233
- 404: ErrorResponse;
11910
+ 404: unknown;
10234
11911
  };
10235
11912
 
10236
- export type GetRepoSecurityError = GetRepoSecurityErrors[keyof GetRepoSecurityErrors];
10237
-
10238
- export type GetRepoSecurityResponses = {
11913
+ export type ListPypiTracksResponses = {
10239
11914
  /**
10240
- * Repository security config and score
11915
+ * tracks declarations
10241
11916
  */
10242
- 200: RepoSecurityResponse;
11917
+ 200: PypiTracksListResponse;
10243
11918
  };
10244
11919
 
10245
- export type GetRepoSecurityResponse = GetRepoSecurityResponses[keyof GetRepoSecurityResponses];
11920
+ export type ListPypiTracksResponse = ListPypiTracksResponses[keyof ListPypiTracksResponses];
10246
11921
 
10247
- export type UpdateRepoSecurityData = {
10248
- body: UpsertScanConfigRequest;
11922
+ export type DeletePypiTrackData = {
11923
+ body?: never;
10249
11924
  path: {
10250
11925
  /**
10251
11926
  * Repository key
10252
11927
  */
10253
11928
  key: string;
11929
+ /**
11930
+ * Project name (PEP 503 normalized server-side)
11931
+ */
11932
+ project: string;
10254
11933
  };
10255
11934
  query?: never;
10256
- url: '/api/v1/repositories/{key}/security';
11935
+ url: '/api/v1/repositories/{key}/pypi-tracks/{project}';
11936
+ };
11937
+
11938
+ export type DeletePypiTrackErrors = {
11939
+ /**
11940
+ * Authentication required
11941
+ */
11942
+ 401: unknown;
11943
+ /**
11944
+ * Repository not found
11945
+ */
11946
+ 404: unknown;
11947
+ };
11948
+
11949
+ export type DeletePypiTrackResponses = {
11950
+ /**
11951
+ * tracks declaration removed (idempotent)
11952
+ */
11953
+ 204: void;
11954
+ };
11955
+
11956
+ export type DeletePypiTrackResponse = DeletePypiTrackResponses[keyof DeletePypiTrackResponses];
11957
+
11958
+ export type PutPypiTrackData = {
11959
+ body: PypiTrackRequest;
11960
+ path: {
11961
+ /**
11962
+ * Repository key
11963
+ */
11964
+ key: string;
11965
+ /**
11966
+ * Project name (PEP 503 normalized server-side)
11967
+ */
11968
+ project: string;
11969
+ };
11970
+ query?: never;
11971
+ url: '/api/v1/repositories/{key}/pypi-tracks/{project}';
11972
+ };
11973
+
11974
+ export type PutPypiTrackErrors = {
11975
+ /**
11976
+ * Invalid request or repository type
11977
+ */
11978
+ 400: unknown;
11979
+ /**
11980
+ * Authentication required
11981
+ */
11982
+ 401: unknown;
11983
+ /**
11984
+ * Repository not found
11985
+ */
11986
+ 404: unknown;
11987
+ };
11988
+
11989
+ export type PutPypiTrackResponses = {
11990
+ /**
11991
+ * tracks declaration stored
11992
+ */
11993
+ 200: PypiTrackResponse;
11994
+ };
11995
+
11996
+ export type PutPypiTrackResponse = PutPypiTrackResponses[keyof PutPypiTrackResponses];
11997
+
11998
+ export type DeleteRoutingRulesData = {
11999
+ body?: never;
12000
+ path: {
12001
+ /**
12002
+ * Repository key
12003
+ */
12004
+ key: string;
12005
+ };
12006
+ query?: never;
12007
+ url: '/api/v1/repositories/{key}/routing-rules';
12008
+ };
12009
+
12010
+ export type DeleteRoutingRulesErrors = {
12011
+ /**
12012
+ * Authentication required
12013
+ */
12014
+ 401: unknown;
12015
+ /**
12016
+ * Repository not found
12017
+ */
12018
+ 404: unknown;
12019
+ };
12020
+
12021
+ export type DeleteRoutingRulesResponses = {
12022
+ /**
12023
+ * Routing rules deleted
12024
+ */
12025
+ 200: unknown;
12026
+ };
12027
+
12028
+ export type GetRoutingRulesData = {
12029
+ body?: never;
12030
+ path: {
12031
+ /**
12032
+ * Repository key
12033
+ */
12034
+ key: string;
12035
+ };
12036
+ query?: never;
12037
+ url: '/api/v1/repositories/{key}/routing-rules';
12038
+ };
12039
+
12040
+ export type GetRoutingRulesErrors = {
12041
+ /**
12042
+ * Repository not found
12043
+ */
12044
+ 404: unknown;
12045
+ };
12046
+
12047
+ export type GetRoutingRulesResponses = {
12048
+ /**
12049
+ * Current routing rules
12050
+ */
12051
+ 200: RoutingRulesResponse;
12052
+ };
12053
+
12054
+ export type GetRoutingRulesResponse = GetRoutingRulesResponses[keyof GetRoutingRulesResponses];
12055
+
12056
+ export type SetRoutingRulesData = {
12057
+ body: SetRoutingRulesRequest;
12058
+ path: {
12059
+ /**
12060
+ * Repository key
12061
+ */
12062
+ key: string;
12063
+ };
12064
+ query?: never;
12065
+ url: '/api/v1/repositories/{key}/routing-rules';
12066
+ };
12067
+
12068
+ export type SetRoutingRulesErrors = {
12069
+ /**
12070
+ * Invalid rule (bad regex or capture reference)
12071
+ */
12072
+ 400: unknown;
12073
+ /**
12074
+ * Authentication required
12075
+ */
12076
+ 401: unknown;
12077
+ /**
12078
+ * Repository not found
12079
+ */
12080
+ 404: unknown;
12081
+ };
12082
+
12083
+ export type SetRoutingRulesResponses = {
12084
+ /**
12085
+ * Routing rules saved
12086
+ */
12087
+ 200: RoutingRulesResponse;
12088
+ };
12089
+
12090
+ export type SetRoutingRulesResponse = SetRoutingRulesResponses[keyof SetRoutingRulesResponses];
12091
+
12092
+ export type GetRepoSecurityData = {
12093
+ body?: never;
12094
+ path: {
12095
+ /**
12096
+ * Repository key
12097
+ */
12098
+ key: string;
12099
+ };
12100
+ query?: never;
12101
+ url: '/api/v1/repositories/{key}/security';
12102
+ };
12103
+
12104
+ export type GetRepoSecurityErrors = {
12105
+ /**
12106
+ * Repository not found
12107
+ */
12108
+ 404: ErrorResponse;
12109
+ };
12110
+
12111
+ export type GetRepoSecurityError = GetRepoSecurityErrors[keyof GetRepoSecurityErrors];
12112
+
12113
+ export type GetRepoSecurityResponses = {
12114
+ /**
12115
+ * Repository security config and score
12116
+ */
12117
+ 200: RepoSecurityResponse;
12118
+ };
12119
+
12120
+ export type GetRepoSecurityResponse = GetRepoSecurityResponses[keyof GetRepoSecurityResponses];
12121
+
12122
+ export type UpdateRepoSecurityData = {
12123
+ body: UpsertScanConfigRequest;
12124
+ path: {
12125
+ /**
12126
+ * Repository key
12127
+ */
12128
+ key: string;
12129
+ };
12130
+ query?: never;
12131
+ url: '/api/v1/repositories/{key}/security';
12132
+ };
12133
+
12134
+ export type UpdateRepoSecurityErrors = {
12135
+ /**
12136
+ * Repository not found
12137
+ */
12138
+ 404: ErrorResponse;
12139
+ };
12140
+
12141
+ export type UpdateRepoSecurityError = UpdateRepoSecurityErrors[keyof UpdateRepoSecurityErrors];
12142
+
12143
+ export type UpdateRepoSecurityResponses = {
12144
+ /**
12145
+ * Repository security config updated
12146
+ */
12147
+ 200: ScanConfigResponse;
12148
+ };
12149
+
12150
+ export type UpdateRepoSecurityResponse = UpdateRepoSecurityResponses[keyof UpdateRepoSecurityResponses];
12151
+
12152
+ export type ListRepoScansData = {
12153
+ body?: never;
12154
+ path: {
12155
+ /**
12156
+ * Repository key
12157
+ */
12158
+ key: string;
12159
+ };
12160
+ query?: {
12161
+ repository_id?: string | null;
12162
+ artifact_id?: string | null;
12163
+ status?: string | null;
12164
+ page?: number | null;
12165
+ per_page?: number | null;
12166
+ };
12167
+ url: '/api/v1/repositories/{key}/security/scans';
12168
+ };
12169
+
12170
+ export type ListRepoScansErrors = {
12171
+ /**
12172
+ * Repository not found
12173
+ */
12174
+ 404: ErrorResponse;
12175
+ };
12176
+
12177
+ export type ListRepoScansError = ListRepoScansErrors[keyof ListRepoScansErrors];
12178
+
12179
+ export type ListRepoScansResponses = {
12180
+ /**
12181
+ * Paginated list of scans for a repository
12182
+ */
12183
+ 200: ScanListResponse;
12184
+ };
12185
+
12186
+ export type ListRepoScansResponse = ListRepoScansResponses[keyof ListRepoScansResponses];
12187
+
12188
+ export type TestUpstreamData = {
12189
+ body?: never;
12190
+ path: {
12191
+ /**
12192
+ * Repository key
12193
+ */
12194
+ key: string;
12195
+ };
12196
+ query?: never;
12197
+ url: '/api/v1/repositories/{key}/test-upstream';
12198
+ };
12199
+
12200
+ export type TestUpstreamErrors = {
12201
+ /**
12202
+ * Repository is not remote or has no upstream URL
12203
+ */
12204
+ 400: unknown;
12205
+ /**
12206
+ * Authentication required
12207
+ */
12208
+ 401: unknown;
12209
+ /**
12210
+ * Repository not found
12211
+ */
12212
+ 404: unknown;
12213
+ /**
12214
+ * Upstream unreachable
12215
+ */
12216
+ 502: unknown;
12217
+ };
12218
+
12219
+ export type TestUpstreamResponses = {
12220
+ /**
12221
+ * Upstream reachable
12222
+ */
12223
+ 200: unknown;
12224
+ };
12225
+
12226
+ export type ListRepoTokensData = {
12227
+ body?: never;
12228
+ path: {
12229
+ /**
12230
+ * Repository key
12231
+ */
12232
+ key: string;
12233
+ };
12234
+ query?: never;
12235
+ url: '/api/v1/repositories/{key}/tokens';
12236
+ };
12237
+
12238
+ export type ListRepoTokensErrors = {
12239
+ /**
12240
+ * Not authenticated
12241
+ */
12242
+ 401: unknown;
12243
+ /**
12244
+ * Insufficient permissions
12245
+ */
12246
+ 403: unknown;
12247
+ /**
12248
+ * Repository not found
12249
+ */
12250
+ 404: unknown;
12251
+ };
12252
+
12253
+ export type ListRepoTokensResponses = {
12254
+ /**
12255
+ * List of tokens on this repository
12256
+ */
12257
+ 200: RepoTokenListResponse;
12258
+ };
12259
+
12260
+ export type ListRepoTokensResponse = ListRepoTokensResponses[keyof ListRepoTokensResponses];
12261
+
12262
+ export type CreateRepoTokenData = {
12263
+ body: CreateRepoTokenRequest;
12264
+ path: {
12265
+ /**
12266
+ * Repository key
12267
+ */
12268
+ key: string;
12269
+ };
12270
+ query?: never;
12271
+ url: '/api/v1/repositories/{key}/tokens';
10257
12272
  };
10258
12273
 
10259
- export type UpdateRepoSecurityErrors = {
12274
+ export type CreateRepoTokenErrors = {
12275
+ /**
12276
+ * Validation error
12277
+ */
12278
+ 400: unknown;
12279
+ /**
12280
+ * Not authenticated
12281
+ */
12282
+ 401: unknown;
12283
+ /**
12284
+ * Insufficient permissions
12285
+ */
12286
+ 403: unknown;
10260
12287
  /**
10261
12288
  * Repository not found
10262
12289
  */
10263
- 404: ErrorResponse;
12290
+ 404: unknown;
10264
12291
  };
10265
12292
 
10266
- export type UpdateRepoSecurityError = UpdateRepoSecurityErrors[keyof UpdateRepoSecurityErrors];
10267
-
10268
- export type UpdateRepoSecurityResponses = {
12293
+ export type CreateRepoTokenResponses = {
10269
12294
  /**
10270
- * Repository security config updated
12295
+ * Token created (value shown once)
10271
12296
  */
10272
- 200: ScanConfigResponse;
12297
+ 200: CreateRepoTokenResponse;
10273
12298
  };
10274
12299
 
10275
- export type UpdateRepoSecurityResponse = UpdateRepoSecurityResponses[keyof UpdateRepoSecurityResponses];
12300
+ export type CreateRepoTokenResponse2 = CreateRepoTokenResponses[keyof CreateRepoTokenResponses];
10276
12301
 
10277
- export type ListRepoScansData = {
12302
+ export type RevokeRepoTokenData = {
10278
12303
  body?: never;
10279
12304
  path: {
10280
12305
  /**
10281
12306
  * Repository key
10282
12307
  */
10283
12308
  key: string;
12309
+ /**
12310
+ * Token ID
12311
+ */
12312
+ token_id: string;
10284
12313
  };
10285
- query?: {
10286
- repository_id?: string | null;
10287
- artifact_id?: string | null;
10288
- status?: string | null;
10289
- page?: number | null;
10290
- per_page?: number | null;
10291
- };
10292
- url: '/api/v1/repositories/{key}/security/scans';
12314
+ query?: never;
12315
+ url: '/api/v1/repositories/{key}/tokens/{token_id}';
10293
12316
  };
10294
12317
 
10295
- export type ListRepoScansErrors = {
12318
+ export type RevokeRepoTokenErrors = {
10296
12319
  /**
10297
- * Repository not found
12320
+ * Not authenticated
10298
12321
  */
10299
- 404: ErrorResponse;
12322
+ 401: unknown;
12323
+ /**
12324
+ * Insufficient permissions
12325
+ */
12326
+ 403: unknown;
12327
+ /**
12328
+ * Repository or token not found
12329
+ */
12330
+ 404: unknown;
10300
12331
  };
10301
12332
 
10302
- export type ListRepoScansError = ListRepoScansErrors[keyof ListRepoScansErrors];
10303
-
10304
- export type ListRepoScansResponses = {
12333
+ export type RevokeRepoTokenResponses = {
10305
12334
  /**
10306
- * Paginated list of scans for a repository
12335
+ * Token revoked
10307
12336
  */
10308
- 200: ScanListResponse;
12337
+ 204: void;
10309
12338
  };
10310
12339
 
10311
- export type ListRepoScansResponse = ListRepoScansResponses[keyof ListRepoScansResponses];
12340
+ export type RevokeRepoTokenResponse = RevokeRepoTokenResponses[keyof RevokeRepoTokenResponses];
10312
12341
 
10313
- export type TestUpstreamData = {
12342
+ export type GetRepoTokenData = {
10314
12343
  body?: never;
10315
12344
  path: {
10316
12345
  /**
10317
12346
  * Repository key
10318
12347
  */
10319
12348
  key: string;
12349
+ /**
12350
+ * Token ID
12351
+ */
12352
+ token_id: string;
10320
12353
  };
10321
12354
  query?: never;
10322
- url: '/api/v1/repositories/{key}/test-upstream';
12355
+ url: '/api/v1/repositories/{key}/tokens/{token_id}';
10323
12356
  };
10324
12357
 
10325
- export type TestUpstreamErrors = {
10326
- /**
10327
- * Repository is not remote or has no upstream URL
10328
- */
10329
- 400: unknown;
12358
+ export type GetRepoTokenErrors = {
10330
12359
  /**
10331
- * Authentication required
12360
+ * Not authenticated
10332
12361
  */
10333
12362
  401: unknown;
10334
12363
  /**
10335
- * Repository not found
12364
+ * Insufficient permissions
10336
12365
  */
10337
- 404: unknown;
12366
+ 403: unknown;
10338
12367
  /**
10339
- * Upstream unreachable
12368
+ * Repository or token not found
10340
12369
  */
10341
- 502: unknown;
12370
+ 404: unknown;
10342
12371
  };
10343
12372
 
10344
- export type TestUpstreamResponses = {
12373
+ export type GetRepoTokenResponses = {
10345
12374
  /**
10346
- * Upstream reachable
12375
+ * Token details
10347
12376
  */
10348
- 200: unknown;
12377
+ 200: RepoTokenResponse;
10349
12378
  };
10350
12379
 
12380
+ export type GetRepoTokenResponse = GetRepoTokenResponses[keyof GetRepoTokenResponses];
12381
+
10351
12382
  export type SetUpstreamAuthData = {
10352
12383
  body: UpstreamAuthRequest;
10353
12384
  path: {
@@ -10486,16 +12517,83 @@ export type CheckLicenseComplianceResponses = {
10486
12517
 
10487
12518
  export type CheckLicenseComplianceResponse = CheckLicenseComplianceResponses[keyof CheckLicenseComplianceResponses];
10488
12519
 
10489
- export type GetCveHistoryData = {
12520
+ export type GetCveHistoryByArtifactData = {
10490
12521
  body?: never;
10491
12522
  path: {
10492
12523
  /**
10493
- * Artifact ID
12524
+ * Artifact UUID
10494
12525
  */
10495
12526
  artifact_id: string;
10496
12527
  };
10497
12528
  query?: never;
10498
- url: '/api/v1/sbom/cve/history/{artifact_id}';
12529
+ url: '/api/v1/sbom/cve/history/by-artifact/{artifact_id}';
12530
+ };
12531
+
12532
+ export type GetCveHistoryByArtifactErrors = {
12533
+ /**
12534
+ * Caller does not have access to this artifact's repository
12535
+ */
12536
+ 403: unknown;
12537
+ /**
12538
+ * Artifact not found
12539
+ */
12540
+ 404: unknown;
12541
+ };
12542
+
12543
+ export type GetCveHistoryByArtifactResponses = {
12544
+ /**
12545
+ * CVE history entries
12546
+ */
12547
+ 200: Array<CveHistoryEntry>;
12548
+ };
12549
+
12550
+ export type GetCveHistoryByArtifactResponse = GetCveHistoryByArtifactResponses[keyof GetCveHistoryByArtifactResponses];
12551
+
12552
+ export type GetCveHistoryByCveData = {
12553
+ body?: never;
12554
+ path: {
12555
+ /**
12556
+ * CVE identifier (e.g. CVE-2019-10744)
12557
+ */
12558
+ cve_id: string;
12559
+ };
12560
+ query?: never;
12561
+ url: '/api/v1/sbom/cve/history/by-cve/{cve_id}';
12562
+ };
12563
+
12564
+ export type GetCveHistoryByCveErrors = {
12565
+ /**
12566
+ * Path id is not a valid CVE identifier
12567
+ */
12568
+ 400: unknown;
12569
+ };
12570
+
12571
+ export type GetCveHistoryByCveResponses = {
12572
+ /**
12573
+ * CVE history entries
12574
+ */
12575
+ 200: Array<CveHistoryEntry>;
12576
+ };
12577
+
12578
+ export type GetCveHistoryByCveResponse = GetCveHistoryByCveResponses[keyof GetCveHistoryByCveResponses];
12579
+
12580
+ export type GetCveHistoryData = {
12581
+ body?: never;
12582
+ path: {
12583
+ /**
12584
+ * Artifact UUID or CVE identifier (e.g. CVE-2019-10744). Prefer the typed routes /cve/history/by-artifact/{uuid} or /cve/history/by-cve/{cve_id}.
12585
+ */
12586
+ id: string;
12587
+ };
12588
+ query?: never;
12589
+ url: '/api/v1/sbom/cve/history/{id}';
12590
+ };
12591
+
12592
+ export type GetCveHistoryErrors = {
12593
+ /**
12594
+ * Path id is neither a valid UUID nor a valid CVE identifier
12595
+ */
12596
+ 400: unknown;
10499
12597
  };
10500
12598
 
10501
12599
  export type GetCveHistoryResponses = {
@@ -10507,6 +12605,48 @@ export type GetCveHistoryResponses = {
10507
12605
 
10508
12606
  export type GetCveHistoryResponse = GetCveHistoryResponses[keyof GetCveHistoryResponses];
10509
12607
 
12608
+ export type UpdateCveStatusByArtifactCveData = {
12609
+ body: UpdateCveStatusRequest;
12610
+ path: {
12611
+ /**
12612
+ * Artifact UUID
12613
+ */
12614
+ artifact_id: string;
12615
+ /**
12616
+ * CVE identifier (e.g. CVE-2019-10744)
12617
+ */
12618
+ cve_id: string;
12619
+ };
12620
+ query?: never;
12621
+ url: '/api/v1/sbom/cve/status/by-artifact/{artifact_id}/by-cve/{cve_id}';
12622
+ };
12623
+
12624
+ export type UpdateCveStatusByArtifactCveErrors = {
12625
+ /**
12626
+ * Validation error (e.g. invalid CVE id or unsupported status)
12627
+ */
12628
+ 400: ErrorResponse;
12629
+ /**
12630
+ * Caller does not have access to this artifact's repository
12631
+ */
12632
+ 403: unknown;
12633
+ /**
12634
+ * No scan_findings rows match (artifact_id, cve_id)
12635
+ */
12636
+ 404: unknown;
12637
+ };
12638
+
12639
+ export type UpdateCveStatusByArtifactCveError = UpdateCveStatusByArtifactCveErrors[keyof UpdateCveStatusByArtifactCveErrors];
12640
+
12641
+ export type UpdateCveStatusByArtifactCveResponses = {
12642
+ /**
12643
+ * Updated synth CVE entry
12644
+ */
12645
+ 200: CveHistoryEntry;
12646
+ };
12647
+
12648
+ export type UpdateCveStatusByArtifactCveResponse = UpdateCveStatusByArtifactCveResponses[keyof UpdateCveStatusByArtifactCveResponses];
12649
+
10510
12650
  export type UpdateCveStatusData = {
10511
12651
  body: UpdateCveStatusRequest;
10512
12652
  path: {
@@ -10778,9 +12918,9 @@ export type ConvertSbomError = ConvertSbomErrors[keyof ConvertSbomErrors];
10778
12918
 
10779
12919
  export type ConvertSbomResponses = {
10780
12920
  /**
10781
- * Converted SBOM
12921
+ * Converted SBOM with content
10782
12922
  */
10783
- 200: SbomResponse;
12923
+ 200: SbomContentResponse;
10784
12924
  };
10785
12925
 
10786
12926
  export type ConvertSbomResponse = ConvertSbomResponses[keyof ConvertSbomResponses];
@@ -10975,6 +13115,15 @@ export type GetDashboardData = {
10975
13115
  url: '/api/v1/security/dashboard';
10976
13116
  };
10977
13117
 
13118
+ export type GetDashboardErrors = {
13119
+ /**
13120
+ * Admin privileges required
13121
+ */
13122
+ 403: ErrorResponse;
13123
+ };
13124
+
13125
+ export type GetDashboardError = GetDashboardErrors[keyof GetDashboardErrors];
13126
+
10978
13127
  export type GetDashboardResponses = {
10979
13128
  /**
10980
13129
  * Security dashboard summary
@@ -10997,6 +13146,10 @@ export type RevokeAcknowledgmentData = {
10997
13146
  };
10998
13147
 
10999
13148
  export type RevokeAcknowledgmentErrors = {
13149
+ /**
13150
+ * Admin privileges required
13151
+ */
13152
+ 403: ErrorResponse;
11000
13153
  /**
11001
13154
  * Finding not found
11002
13155
  */
@@ -11027,6 +13180,10 @@ export type AcknowledgeFindingData = {
11027
13180
  };
11028
13181
 
11029
13182
  export type AcknowledgeFindingErrors = {
13183
+ /**
13184
+ * Admin privileges required
13185
+ */
13186
+ 403: ErrorResponse;
11030
13187
  /**
11031
13188
  * Finding not found
11032
13189
  */
@@ -11189,10 +13346,14 @@ export type TriggerScanErrors = {
11189
13346
  * Validation error
11190
13347
  */
11191
13348
  400: ErrorResponse;
13349
+ /**
13350
+ * bypass_dedup requested by non-admin caller
13351
+ */
13352
+ 403: ErrorResponse;
11192
13353
  /**
11193
13354
  * Scanner service not configured
11194
13355
  */
11195
- 500: ErrorResponse;
13356
+ 503: ErrorResponse;
11196
13357
  };
11197
13358
 
11198
13359
  export type TriggerScanError = TriggerScanErrors[keyof TriggerScanErrors];
@@ -11298,6 +13459,15 @@ export type GetAllScoresData = {
11298
13459
  url: '/api/v1/security/scores';
11299
13460
  };
11300
13461
 
13462
+ export type GetAllScoresErrors = {
13463
+ /**
13464
+ * Admin privileges required
13465
+ */
13466
+ 403: ErrorResponse;
13467
+ };
13468
+
13469
+ export type GetAllScoresError = GetAllScoresErrors[keyof GetAllScoresErrors];
13470
+
11301
13471
  export type GetAllScoresResponses = {
11302
13472
  /**
11303
13473
  * All repository security scores
@@ -12127,6 +14297,22 @@ export type TogglePolicyResponses = {
12127
14297
 
12128
14298
  export type TogglePolicyResponse = TogglePolicyResponses[keyof TogglePolicyResponses];
12129
14299
 
14300
+ export type GetSystemConfigData = {
14301
+ body?: never;
14302
+ path?: never;
14303
+ query?: never;
14304
+ url: '/api/v1/system/config';
14305
+ };
14306
+
14307
+ export type GetSystemConfigResponses = {
14308
+ /**
14309
+ * Runtime configuration (security-posture fields admin-only)
14310
+ */
14311
+ 200: SystemConfigResponse;
14312
+ };
14313
+
14314
+ export type GetSystemConfigResponse = GetSystemConfigResponses[keyof GetSystemConfigResponses];
14315
+
12130
14316
  export type GetTreeData = {
12131
14317
  body?: never;
12132
14318
  path?: never;
@@ -12227,6 +14413,10 @@ export type CreateSessionErrors = {
12227
14413
  * Unauthorized
12228
14414
  */
12229
14415
  401: unknown;
14416
+ /**
14417
+ * Forbidden
14418
+ */
14419
+ 403: ErrorResponse;
12230
14420
  /**
12231
14421
  * Repository not found
12232
14422
  */
@@ -12527,6 +14717,42 @@ export type UpdateUserResponses = {
12527
14717
 
12528
14718
  export type UpdateUserResponse = UpdateUserResponses[keyof UpdateUserResponses];
12529
14719
 
14720
+ export type ForcePasswordChangeData = {
14721
+ body?: never;
14722
+ path: {
14723
+ /**
14724
+ * User ID
14725
+ */
14726
+ id: string;
14727
+ };
14728
+ query?: never;
14729
+ url: '/api/v1/users/{id}/force-password-change';
14730
+ };
14731
+
14732
+ export type ForcePasswordChangeErrors = {
14733
+ /**
14734
+ * Only administrators can force password changes
14735
+ */
14736
+ 403: unknown;
14737
+ /**
14738
+ * User not found
14739
+ */
14740
+ 404: unknown;
14741
+ /**
14742
+ * Cannot force password change for SSO users
14743
+ */
14744
+ 422: unknown;
14745
+ };
14746
+
14747
+ export type ForcePasswordChangeResponses = {
14748
+ /**
14749
+ * Flag set successfully
14750
+ */
14751
+ 200: ForcePasswordChangeResponse;
14752
+ };
14753
+
14754
+ export type ForcePasswordChangeResponse2 = ForcePasswordChangeResponses[keyof ForcePasswordChangeResponses];
14755
+
12530
14756
  export type ChangePasswordData = {
12531
14757
  body: ChangePasswordRequest;
12532
14758
  path: {
@@ -12801,13 +15027,17 @@ export type CreateWebhookErrors = {
12801
15027
  * Internal server error
12802
15028
  */
12803
15029
  500: unknown;
15030
+ /**
15031
+ * A secret was supplied but AK_WEBHOOK_SECRET_KEY is not configured, so the secret cannot be encrypted at rest
15032
+ */
15033
+ 503: unknown;
12804
15034
  };
12805
15035
 
12806
15036
  export type CreateWebhookResponses = {
12807
15037
  /**
12808
- * Webhook created successfully
15038
+ * Webhook created. Body includes the raw secret exactly once (omitted when created unsigned).
12809
15039
  */
12810
- 200: WebhookResponse;
15040
+ 200: WebhookSecretCreatedResponse;
12811
15041
  };
12812
15042
 
12813
15043
  export type CreateWebhookResponse = CreateWebhookResponses[keyof CreateWebhookResponses];
@@ -12982,6 +15212,42 @@ export type EnableWebhookResponses = {
12982
15212
  200: unknown;
12983
15213
  };
12984
15214
 
15215
+ export type RotateWebhookSecretData = {
15216
+ body?: never;
15217
+ path: {
15218
+ /**
15219
+ * Webhook ID
15220
+ */
15221
+ id: string;
15222
+ };
15223
+ query?: never;
15224
+ url: '/api/v1/webhooks/{id}/rotate-secret';
15225
+ };
15226
+
15227
+ export type RotateWebhookSecretErrors = {
15228
+ /**
15229
+ * Webhook not found
15230
+ */
15231
+ 404: unknown;
15232
+ /**
15233
+ * A previous rotation overlap window is still active
15234
+ */
15235
+ 409: unknown;
15236
+ /**
15237
+ * Encryption key not configured
15238
+ */
15239
+ 500: unknown;
15240
+ };
15241
+
15242
+ export type RotateWebhookSecretResponses = {
15243
+ /**
15244
+ * Secret rotated. Body includes the new raw secret exactly once.
15245
+ */
15246
+ 200: RotateWebhookSecretResponse;
15247
+ };
15248
+
15249
+ export type RotateWebhookSecretResponse2 = RotateWebhookSecretResponses[keyof RotateWebhookSecretResponses];
15250
+
12985
15251
  export type TestWebhookData = {
12986
15252
  body?: never;
12987
15253
  path: {