@artifact-keeper/sdk 1.1.6 → 1.2.1

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
  */
@@ -1456,11 +1786,30 @@ export type GetCveTrendsQuery = {
1456
1786
  repository_id?: string | null;
1457
1787
  };
1458
1788
 
1789
+ export type GroupDetailResponse = GroupResponse & {
1790
+ /**
1791
+ * Paginated list of group members.
1792
+ */
1793
+ members: Array<GroupMemberResponse>;
1794
+ /**
1795
+ * Total number of members in the group. Clients can compare this against
1796
+ * the length of `members` to determine whether additional pages exist.
1797
+ */
1798
+ members_total: number;
1799
+ };
1800
+
1459
1801
  export type GroupListResponse = {
1460
1802
  items: Array<GroupResponse>;
1461
1803
  pagination: Pagination;
1462
1804
  };
1463
1805
 
1806
+ export type GroupMemberResponse = {
1807
+ display_name?: string | null;
1808
+ joined_at: string;
1809
+ user_id: string;
1810
+ username: string;
1811
+ };
1812
+
1464
1813
  export type GroupResponse = {
1465
1814
  created_at: string;
1466
1815
  description?: string | null;
@@ -1498,7 +1847,7 @@ export type GrowthSummary = {
1498
1847
  export type HealthChecks = {
1499
1848
  database: CheckStatus;
1500
1849
  ldap?: null | CheckStatus;
1501
- meilisearch?: null | CheckStatus;
1850
+ opensearch?: null | CheckStatus;
1502
1851
  security_scanner?: null | CheckStatus;
1503
1852
  storage: CheckStatus;
1504
1853
  };
@@ -1565,6 +1914,23 @@ export type InstallFromLocalRequest = {
1565
1914
  path: string;
1566
1915
  };
1567
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
+
1568
1934
  export type IssueResponse = {
1569
1935
  artifact_id: string;
1570
1936
  category: string;
@@ -1682,6 +2048,19 @@ export type LifecyclePolicy = {
1682
2048
  };
1683
2049
 
1684
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;
1685
2064
  page?: number | null;
1686
2065
  path_prefix?: string | null;
1687
2066
  per_page?: number | null;
@@ -1783,6 +2162,55 @@ export type MatchedRepoSchema = {
1783
2162
  key: string;
1784
2163
  };
1785
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
+
1786
2214
  export type MembersRequest = {
1787
2215
  user_ids: Array<string>;
1788
2216
  };
@@ -1909,6 +2337,83 @@ export type NetworkProfileBody = {
1909
2337
  sync_window_timezone?: string | null;
1910
2338
  };
1911
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
+
1912
2417
  export type OidcConfigResponse = {
1913
2418
  attribute_mapping: {
1914
2419
  [key: string]: unknown;
@@ -1920,7 +2425,9 @@ export type OidcConfigResponse = {
1920
2425
  id: string;
1921
2426
  is_enabled: boolean;
1922
2427
  issuer_url: string;
2428
+ map_groups_to_groups: boolean;
1923
2429
  name: string;
2430
+ pkce_enabled: boolean;
1924
2431
  scopes: Array<string>;
1925
2432
  updated_at: string;
1926
2433
  };
@@ -2021,6 +2528,15 @@ export type PaginationInfo = {
2021
2528
  total_pages: number;
2022
2529
  };
2023
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
+
2024
2540
  export type PeerInstanceListResponse = {
2025
2541
  items: Array<PeerInstanceResponse>;
2026
2542
  total: number;
@@ -2120,6 +2636,23 @@ export type PermissionRow = {
2120
2636
  updated_at: string;
2121
2637
  };
2122
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
+
2123
2656
  export type PluginConfigResponse = {
2124
2657
  config: {
2125
2658
  [key: string]: unknown;
@@ -2163,7 +2696,27 @@ export type PluginResponse = {
2163
2696
  };
2164
2697
 
2165
2698
  /**
2166
- * Plugin status
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
+
2718
+ /**
2719
+ * Plugin status
2167
2720
  */
2168
2721
  export type PluginStatus = 'active' | 'disabled' | 'error';
2169
2722
 
@@ -2259,7 +2812,11 @@ export type ProbeBody = {
2259
2812
  export type PromoteArtifactRequest = {
2260
2813
  notes?: string | null;
2261
2814
  skip_policy_check?: boolean;
2262
- target_repository: string;
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;
2263
2820
  };
2264
2821
 
2265
2822
  export type PromotionHistoryEntry = {
@@ -2322,6 +2879,50 @@ export type PromotionRuleResponse = {
2322
2879
  updated_at: string;
2323
2880
  };
2324
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
+
2325
2926
  export type QuickSearchResponse = {
2326
2927
  results: Array<SearchResultItem>;
2327
2928
  };
@@ -2373,6 +2974,13 @@ export type RejectArtifactRequest = {
2373
2974
  reason: string;
2374
2975
  };
2375
2976
 
2977
+ export type RejectRequest = {
2978
+ /**
2979
+ * Optional reason for rejection.
2980
+ */
2981
+ reason?: string | null;
2982
+ };
2983
+
2376
2984
  export type RejectionResponse = {
2377
2985
  artifact_id: string;
2378
2986
  reason: string;
@@ -2381,6 +2989,21 @@ export type RejectionResponse = {
2381
2989
  source: string;
2382
2990
  };
2383
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
+
2384
3007
  export type RemoteInstanceResponse = {
2385
3008
  created_at: string;
2386
3009
  id: string;
@@ -2417,6 +3040,30 @@ export type RepoSelectorSchema = {
2417
3040
  match_repos?: Array<string>;
2418
3041
  };
2419
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
+
2420
3067
  export type RepositoryAssessment = {
2421
3068
  artifact_count: number;
2422
3069
  compatibility: string;
@@ -2433,6 +3080,12 @@ export type RepositoryListResponse = {
2433
3080
  };
2434
3081
 
2435
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;
2436
3089
  created_at: string;
2437
3090
  description?: string | null;
2438
3091
  format: string;
@@ -2440,6 +3093,21 @@ export type RepositoryResponse = {
2440
3093
  is_public: boolean;
2441
3094
  key: string;
2442
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;
2443
3111
  quota_bytes?: number | null;
2444
3112
  repo_type: string;
2445
3113
  storage_used_bytes: number;
@@ -2490,6 +3158,30 @@ export type RepositoryStorageBreakdown = {
2490
3158
  storage_bytes: number;
2491
3159
  };
2492
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
+
2493
3185
  /**
2494
3186
  * Response for password reset
2495
3187
  */
@@ -2527,6 +3219,43 @@ export type RoleResponse = {
2527
3219
  permissions: Array<string>;
2528
3220
  };
2529
3221
 
3222
+ /**
3223
+ * Response returned by the rotate-secret endpoint.
3224
+ */
3225
+ export type RotateWebhookSecretResponse = {
3226
+ id: string;
3227
+ /**
3228
+ * When the previously active secret stops being accepted.
3229
+ */
3230
+ previous_secret_expires_at: string;
3231
+ /**
3232
+ * Raw signing secret produced by this rotation. Shown exactly once.
3233
+ */
3234
+ secret: string;
3235
+ secret_digest: string;
3236
+ };
3237
+
3238
+ /**
3239
+ * A single routing rule that maps an incoming path to a rewritten path.
3240
+ */
3241
+ export type RoutingRule = {
3242
+ /**
3243
+ * Regex pattern matched against the full request path.
3244
+ * Use capture groups to extract portions for the rewrite template.
3245
+ */
3246
+ path_pattern: string;
3247
+ /**
3248
+ * Rewrite template. Use `$1`, `$2`, etc. to reference captured groups
3249
+ * from `path_pattern`.
3250
+ */
3251
+ rewrite_to: string;
3252
+ };
3253
+
3254
+ export type RoutingRulesResponse = {
3255
+ repository_key: string;
3256
+ rules: Array<RoutingRule>;
3257
+ };
3258
+
2530
3259
  export type RuleEvaluationResponse = {
2531
3260
  passed: boolean;
2532
3261
  rule_id: string;
@@ -2549,6 +3278,14 @@ export type RuleResponse = {
2549
3278
  version_constraint: string;
2550
3279
  };
2551
3280
 
3281
+ /**
3282
+ * Result of `POST /:id/repositories/:repo_id/sync` (run-now trigger).
3283
+ */
3284
+ export type RunNowResponse = {
3285
+ status: string;
3286
+ tasks_queued: number;
3287
+ };
3288
+
2552
3289
  export type SamlAcsForm = {
2553
3290
  RelayState?: string | null;
2554
3291
  SAMLResponse: string;
@@ -2627,15 +3364,47 @@ export type ScanResponse = {
2627
3364
  high_count: number;
2628
3365
  id: string;
2629
3366
  info_count: number;
3367
+ /**
3368
+ * True when the row was synthesized by the dedup path (`copy_scan_results`)
3369
+ * because a prior scan with the same `(checksum_sha256, scan_type)` pair
3370
+ * already existed within the dedup TTL. No scanner was actually invoked
3371
+ * for this row; counts and findings were copied from `source_scan_id`.
3372
+ */
3373
+ is_reused: boolean;
2630
3374
  low_count: number;
2631
3375
  medium_count: number;
2632
3376
  repository_id: string;
2633
3377
  scan_type: string;
2634
3378
  scanner_version?: string | null;
3379
+ /**
3380
+ * When `is_reused` is true, the `id` of the source scan whose results
3381
+ * were copied. Useful for distinguishing "fresh scan" from "deduped
3382
+ * satisfaction" in release-gate provenance checks. None for original
3383
+ * (non-reused) scans.
3384
+ */
3385
+ source_scan_id?: string | null;
2635
3386
  started_at?: string | null;
2636
3387
  status: string;
2637
3388
  };
2638
3389
 
3390
+ /**
3391
+ * Scanner availability flags.
3392
+ */
3393
+ export type ScannersConfig = {
3394
+ /**
3395
+ * Whether the Dependency-Track integration is configured.
3396
+ */
3397
+ dependency_track_enabled: boolean;
3398
+ /**
3399
+ * Whether the OpenSCAP compliance scanner is configured.
3400
+ */
3401
+ openscap_enabled: boolean;
3402
+ /**
3403
+ * Whether the Trivy vulnerability scanner is configured.
3404
+ */
3405
+ trivy_enabled: boolean;
3406
+ };
3407
+
2639
3408
  export type ScoreResponse = {
2640
3409
  acknowledged_count: number;
2641
3410
  calculated_at: string;
@@ -2740,6 +3509,22 @@ export type SetPeerLabelsRequest = {
2740
3509
  labels: Array<PeerLabelEntrySchema>;
2741
3510
  };
2742
3511
 
3512
+ export type SetReleaseTargetRequest = {
3513
+ /**
3514
+ * Repository key of the release (local) repository to link.
3515
+ * Pass `null` or omit to remove the link.
3516
+ */
3517
+ release_repository_key?: string | null;
3518
+ };
3519
+
3520
+ export type SetRoutingRulesRequest = {
3521
+ /**
3522
+ * Ordered list of routing rules. Each rule specifies a regex pattern and
3523
+ * a rewrite template. Rules are evaluated in order during proxy requests.
3524
+ */
3525
+ rules: Array<RoutingRule>;
3526
+ };
3527
+
2743
3528
  /**
2744
3529
  * Response body for the setup status endpoint.
2745
3530
  */
@@ -2779,6 +3564,33 @@ export type SigningKeyPublic = {
2779
3564
  uid_name?: string | null;
2780
3565
  };
2781
3566
 
3567
+ /**
3568
+ * Request body for the SMTP test endpoint.
3569
+ */
3570
+ export type SmtpTestRequest = {
3571
+ /**
3572
+ * Recipient email address for the test message.
3573
+ *
3574
+ * Accepts `recipient` as an alias for backward compatibility with Web UI
3575
+ * versions <= 1.1.3, which send `{"recipient": "..."}`.
3576
+ */
3577
+ to: string;
3578
+ };
3579
+
3580
+ /**
3581
+ * Response from the SMTP test endpoint.
3582
+ */
3583
+ export type SmtpTestResponse = {
3584
+ /**
3585
+ * Human-readable status message.
3586
+ */
3587
+ message: string;
3588
+ /**
3589
+ * Whether the test email was sent successfully.
3590
+ */
3591
+ success: boolean;
3592
+ };
3593
+
2782
3594
  export type SourceConnectionRow = {
2783
3595
  auth_type: string;
2784
3596
  created_at: string;
@@ -2881,6 +3693,23 @@ export type SubmitResponse = {
2881
3693
  marked_submitted: number;
2882
3694
  };
2883
3695
 
3696
+ /**
3697
+ * Detailed subscription view (mode, schedule, filter) for a single (peer, repo) pair.
3698
+ */
3699
+ export type SubscriptionResponse = {
3700
+ created_at: string;
3701
+ id: string;
3702
+ last_replicated_at?: string | null;
3703
+ peer_instance_id: string;
3704
+ replication_filter: {
3705
+ [key: string]: unknown;
3706
+ };
3707
+ replication_mode?: string | null;
3708
+ replication_schedule?: string | null;
3709
+ repository_id: string;
3710
+ sync_enabled: boolean;
3711
+ };
3712
+
2884
3713
  export type SuggestResponse = {
2885
3714
  suggestions: Array<string>;
2886
3715
  };
@@ -2906,6 +3735,12 @@ export type SyncPolicyResponse = {
2906
3735
  created_at: string;
2907
3736
  description: string;
2908
3737
  enabled: boolean;
3738
+ /**
3739
+ * Convenience glob filter, mirrored from `artifact_filter.include_paths`.
3740
+ * Round-trips the single-pattern shorthand accepted on create
3741
+ * (e.g. `"*.tar.gz"`). Empty when no include pattern is set.
3742
+ */
3743
+ filter: string;
2909
3744
  id: string;
2910
3745
  name: string;
2911
3746
  peer_selector: {
@@ -2923,11 +3758,82 @@ export type SyncPolicyResponse = {
2923
3758
  export type SyncTaskResponse = {
2924
3759
  artifact_id: string;
2925
3760
  artifact_size: number;
3761
+ /**
3762
+ * When the task was enqueued. Lets clients tell a freshly-scheduled task
3763
+ * apart from a stale queue entry (used by the replication-schedule check).
3764
+ * Serialized as whole-second RFC3339 with a `Z` suffix
3765
+ * (e.g. `2026-05-29T12:34:56Z`) so simple ISO8601 parsers can consume it.
3766
+ */
3767
+ created_at: string;
2926
3768
  id: string;
2927
3769
  priority: number;
3770
+ /**
3771
+ * When the worker began transferring, if it has started. Same format as
3772
+ * `created_at`.
3773
+ */
3774
+ started_at?: string | null;
3775
+ /**
3776
+ * Task status (e.g. "pending"). Listing currently returns pending tasks.
3777
+ */
3778
+ status: string;
2928
3779
  storage_key: string;
2929
3780
  };
2930
3781
 
3782
+ /**
3783
+ * Public runtime configuration values.
3784
+ *
3785
+ * This response intentionally omits all secrets, credentials, and internal
3786
+ * connection strings. Only values useful for UI/client behavior are included.
3787
+ */
3788
+ export type SystemConfigResponse = {
3789
+ /**
3790
+ * Authentication provider availability.
3791
+ */
3792
+ auth: AuthConfig;
3793
+ /**
3794
+ * Whether the instance is running in demo mode (writes blocked).
3795
+ */
3796
+ demo_mode: boolean;
3797
+ /**
3798
+ * Whether anonymous (unauthenticated) access is permitted at all (issue #850).
3799
+ * When `false`, the server rejects all unauthenticated requests except for
3800
+ * the login, setup, health, and OCI challenge endpoints. Frontends should
3801
+ * hide UI affordances that imply public access (e.g. the "public repo"
3802
+ * toggle) and redirect unauthenticated users to the login page.
3803
+ */
3804
+ guest_access_enabled: boolean;
3805
+ /**
3806
+ * Maximum upload size in bytes (0 means no limit).
3807
+ */
3808
+ max_upload_size_bytes: number;
3809
+ /**
3810
+ * OIDC issuer URL, if configured. This is public information needed by
3811
+ * clients to initiate the OIDC flow.
3812
+ */
3813
+ oidc_issuer?: string | null;
3814
+ /**
3815
+ * Fine-grained permissions enforcement status. Permission rules can be
3816
+ * managed via /api/v1/permissions and are actively enforced.
3817
+ */
3818
+ permissions: PermissionsConfig;
3819
+ /**
3820
+ * Plugin signature-verification (supply-chain) policy status.
3821
+ */
3822
+ plugin_signing: PluginSigningConfig;
3823
+ /**
3824
+ * Scanner availability.
3825
+ */
3826
+ scanners: ScannersConfig;
3827
+ /**
3828
+ * Search engine type: "opensearch" when configured, "database" otherwise.
3829
+ */
3830
+ search_engine: string;
3831
+ /**
3832
+ * Storage backend type (e.g. "filesystem", "s3", "gcs", "azure").
3833
+ */
3834
+ storage_backend: string;
3835
+ };
3836
+
2931
3837
  export type SystemSettings = {
2932
3838
  allow_anonymous_download: boolean;
2933
3839
  audit_retention_days: number;
@@ -3115,12 +4021,45 @@ export type TriggerChecksResponse = {
3115
4021
 
3116
4022
  export type TriggerScanRequest = {
3117
4023
  artifact_id?: string | null;
4024
+ /**
4025
+ * Skip the hash-based scan dedup short-circuit when running this scan.
4026
+ *
4027
+ * Defaults to `false`. Normal trigger calls dedup against prior
4028
+ * completed scans for the same checksum + scan_type so a freshly
4029
+ * uploaded byte-identical artifact reuses the existing result instead
4030
+ * of re-running the scanner. When `true`, that dedup is skipped: the
4031
+ * scanner runs against the bytes again and writes a fresh
4032
+ * `scan_results` row. Use this to recover from a silently-broken
4033
+ * prior scan (e.g. an extraction bug producing a completed,
4034
+ * zero-finding row that masks the real findings until the dedup TTL
4035
+ * expires; see #1469). Costs an extra scan run, so leave it unset
4036
+ * for routine trigger calls.
4037
+ *
4038
+ * **Admin only.** Setting this to `true` bypasses the dedup short-
4039
+ * circuit and fans out unbounded scanner work per artifact. The
4040
+ * `trigger_scan` handler rejects this field with 403 for non-admin
4041
+ * callers, since a non-admin force-rescan path would be a DoS
4042
+ * amplifier (the pre-existing `force=true` was naturally rate-limited
4043
+ * by dedup; `bypass_dedup` removes that safety).
4044
+ */
4045
+ bypass_dedup?: boolean | null;
3118
4046
  repository_id?: string | null;
3119
4047
  };
3120
4048
 
3121
4049
  export type TriggerScanResponse = {
3122
4050
  artifacts_queued: number;
3123
4051
  message: string;
4052
+ /**
4053
+ * Scan result IDs created (one per active scanner) when triggering an
4054
+ * artifact-level scan. Empty for repository-level scans (where the
4055
+ * per-artifact rows are created inside the spawned worker) and for
4056
+ * artifact-level triggers when no scanners are configured.
4057
+ *
4058
+ * Clients (and the release-gate test in artifact-keeper-test#58) should
4059
+ * poll `GET /api/v1/security/scans/{id}` against these IDs rather than
4060
+ * guessing the most-recent scan from `GET /artifacts/{id}/scans`.
4061
+ */
4062
+ scan_result_ids?: Array<string>;
3124
4063
  };
3125
4064
 
3126
4065
  /**
@@ -3192,15 +4131,29 @@ export type UpdateLdapConfigRequest = {
3192
4131
  };
3193
4132
 
3194
4133
  export type UpdateOidcConfigRequest = {
4134
+ /**
4135
+ * Partial update for `attribute_mapping`. Keys present in this object
4136
+ * overwrite the matching keys in the stored mapping. Keys not present
4137
+ * are preserved. To remove a key, set it to `null`. To replace the
4138
+ * whole mapping atomically, set `attribute_mapping_replace = true`.
4139
+ * (See issue #1191.)
4140
+ */
3195
4141
  attribute_mapping?: {
3196
4142
  [key: string]: unknown;
3197
4143
  } | null;
4144
+ /**
4145
+ * When `true`, treat `attribute_mapping` as a wholesale replacement
4146
+ * (legacy behavior). Defaults to `false` — partial merge.
4147
+ */
4148
+ attribute_mapping_replace?: boolean | null;
3198
4149
  auto_create_users?: boolean | null;
3199
4150
  client_id?: string | null;
3200
4151
  client_secret?: string | null;
3201
4152
  is_enabled?: boolean | null;
3202
4153
  issuer_url?: string | null;
4154
+ map_groups_to_groups?: boolean | null;
3203
4155
  name?: string | null;
4156
+ pkce_enabled?: boolean | null;
3204
4157
  scopes?: Array<string> | null;
3205
4158
  };
3206
4159
 
@@ -3210,18 +4163,45 @@ export type UpdatePluginConfigRequest = {
3210
4163
  };
3211
4164
  };
3212
4165
 
4166
+ /**
4167
+ * Partial-update payload for `PUT /security/policies/{id}`.
4168
+ *
4169
+ * Every field is `Option<T>` so clients can send any subset of mutable
4170
+ * columns; omitted fields leave the existing row value untouched. The
4171
+ * previous shape required all of `name`, `max_severity`, `block_unscanned`,
4172
+ * `block_on_fail`, `is_enabled` on every call. That was incompatible with
4173
+ * the release-gate `scan-policy-crud` test (and external callers) which
4174
+ * PATCH a subset like `{max_severity, is_enabled}`; under the strict shape
4175
+ * the request was rejected as a 422 and the boolean toggle silently never
4176
+ * took effect on a follow-up GET. See #1374.
4177
+ *
4178
+ * For `min_staging_hours` / `max_artifact_age_days` the field is the inner
4179
+ * nullable `i32`; "not provided" leaves the column untouched. Explicit
4180
+ * `null` to clear those columns is not currently supported; the release
4181
+ * gate only mutates the bool/enum fields, so the narrower semantics are
4182
+ * sufficient and we avoid an ambiguous JSON contract.
4183
+ */
3213
4184
  export type UpdatePolicyRequest = {
3214
- block_on_fail: boolean;
3215
- block_unscanned: boolean;
3216
- is_enabled: boolean;
4185
+ block_on_fail?: boolean | null;
4186
+ block_unscanned?: boolean | null;
4187
+ is_enabled?: boolean | null;
3217
4188
  max_artifact_age_days?: number | null;
3218
- max_severity: string;
4189
+ max_severity?: string | null;
3219
4190
  min_staging_hours?: number | null;
3220
- name: string;
3221
- require_signature?: boolean;
4191
+ name?: string | null;
4192
+ require_signature?: boolean | null;
3222
4193
  };
3223
4194
 
3224
4195
  export type UpdateRepositoryRequest = {
4196
+ /**
4197
+ * Alias for `is_public`. When set to true, anonymous users can download
4198
+ * artifacts without authentication. Useful for remote (pull-through cache)
4199
+ * repositories that proxy public upstream registries. Write operations
4200
+ * (upload, delete) still require authentication regardless of this setting.
4201
+ * If both `is_public` and `allow_anonymous_access` are provided,
4202
+ * `allow_anonymous_access` takes precedence.
4203
+ */
4204
+ allow_anonymous_access?: boolean | null;
3225
4205
  description?: string | null;
3226
4206
  /**
3227
4207
  * Update the Cargo index upstream URL (stored in `repository_config`).
@@ -3231,7 +4211,31 @@ export type UpdateRepositoryRequest = {
3231
4211
  is_public?: boolean | null;
3232
4212
  key?: string | null;
3233
4213
  name?: string | null;
4214
+ /**
4215
+ * When provided, enables/disables the `promotion_only` policy for this
4216
+ * repository (admin-only). When omitted, the flag is left unchanged.
4217
+ */
4218
+ promotion_only?: boolean | null;
4219
+ /**
4220
+ * Quarantine hold duration in minutes for this repository.
4221
+ * Stored in `repository_config` under `quarantine_duration_minutes`.
4222
+ */
4223
+ quarantine_duration_minutes?: number | null;
4224
+ /**
4225
+ * Enable or disable quarantine period for this repository.
4226
+ * When enabled, newly uploaded artifacts are held until scanned.
4227
+ * Stored in `repository_config` under `quarantine_enabled`.
4228
+ */
4229
+ quarantine_enabled?: boolean | null;
3234
4230
  quota_bytes?: number | null;
4231
+ /**
4232
+ * Link this staging repository to a release (local) repository.
4233
+ * Promotions from this staging repo will default to the linked release repo,
4234
+ * and promotions to any other repo will be rejected.
4235
+ * Pass an empty string to remove the link.
4236
+ * Stored in `repository_config` under `release_repository_id`.
4237
+ */
4238
+ release_repository_key?: string | null;
3235
4239
  };
3236
4240
 
3237
4241
  export type UpdateRuleRequest = {
@@ -3317,13 +4321,25 @@ export type UpsertLicensePolicyRequest = {
3317
4321
 
3318
4322
  /**
3319
4323
  * Request to create or update a scan configuration.
4324
+ *
4325
+ * Every field is optional so a `PUT /repositories/{key}/security` can carry
4326
+ * any subset of mutable columns; fields the client omits keep their existing
4327
+ * value (or fall back to the documented default when the row does not exist
4328
+ * yet). The previous shape required all of `scan_enabled`, `scan_on_upload`,
4329
+ * `scan_on_proxy`, `block_on_policy_violation`, `severity_threshold` on every
4330
+ * call. That was the #1374 bug class on a second entity: a partial PUT (for
4331
+ * example just `{scan_enabled: true}`) either bounced as a 422 or, worse,
4332
+ * silently reset every other column to its default so a follow-up GET showed
4333
+ * the untouched fields stale. The upsert is now a read-modify-write that
4334
+ * merges the patch over the existing row, so multiple fields persist together
4335
+ * and an omitted field is never clobbered. See #1374 / B11.
3320
4336
  */
3321
4337
  export type UpsertScanConfigRequest = {
3322
- block_on_policy_violation: boolean;
3323
- scan_enabled: boolean;
3324
- scan_on_proxy: boolean;
3325
- scan_on_upload: boolean;
3326
- severity_threshold: string;
4338
+ block_on_policy_violation?: boolean | null;
4339
+ scan_enabled?: boolean | null;
4340
+ scan_on_proxy?: boolean | null;
4341
+ scan_on_upload?: boolean | null;
4342
+ severity_threshold?: string | null;
3327
4343
  };
3328
4344
 
3329
4345
  export type UpstreamAuthRequest = {
@@ -3414,6 +4430,12 @@ export type WebhookListResponse = {
3414
4430
 
3415
4431
  export type WebhookResponse = {
3416
4432
  created_at: string;
4433
+ /**
4434
+ * Pinned event payload version (e.g. "2026-04-01"). Determines the
4435
+ * shape of the rendered payload and the value sent in the
4436
+ * `X-ArtifactKeeper-Event-Version` header.
4437
+ */
4438
+ event_schema_version: string;
3417
4439
  events: Array<string>;
3418
4440
  headers?: {
3419
4441
  [key: string]: unknown;
@@ -3422,10 +4444,42 @@ export type WebhookResponse = {
3422
4444
  is_enabled: boolean;
3423
4445
  last_triggered_at?: string | null;
3424
4446
  name: string;
4447
+ payload_template: PayloadTemplate;
3425
4448
  repository_id?: string | null;
4449
+ /**
4450
+ * Short non-reversible identifier for the current signing secret
4451
+ * (`whsec_...abcd`), suitable for display in operator UIs. The raw
4452
+ * secret is never returned by GET or LIST.
4453
+ */
4454
+ secret_digest?: string | null;
4455
+ /**
4456
+ * True while a previous secret is still accepted by the retry path
4457
+ * during a rotation overlap window.
4458
+ */
4459
+ secret_rotation_active?: boolean;
3426
4460
  url: string;
3427
4461
  };
3428
4462
 
4463
+ /**
4464
+ * Response returned exactly once when a webhook is created or its secret
4465
+ * is rotated. The raw `secret` value is not retrievable afterwards.
4466
+ */
4467
+ export type WebhookSecretCreatedResponse = WebhookResponse & {
4468
+ /**
4469
+ * Raw signing secret. Display this to the operator immediately and
4470
+ * instruct them to record it; the server retains only the encrypted
4471
+ * form and a short digest.
4472
+ *
4473
+ * Absent when the webhook was created without a signing secret. This
4474
+ * happens when no secret was supplied and the deployment has no
4475
+ * `AK_WEBHOOK_SECRET_KEY` configured: rather than fail the create with
4476
+ * a 500, the webhook is stored unsigned and deliveries omit the
4477
+ * signature header. Configure the key and rotate the secret later to
4478
+ * enable signing.
4479
+ */
4480
+ secret?: string | null;
4481
+ };
4482
+
3429
4483
  export type GetStaleArtifactsData = {
3430
4484
  body?: never;
3431
4485
  path?: never;
@@ -3688,6 +4742,10 @@ export type CancelBackupErrors = {
3688
4742
  * Backup not found
3689
4743
  */
3690
4744
  404: unknown;
4745
+ /**
4746
+ * Backup is not in a cancellable state
4747
+ */
4748
+ 409: unknown;
3691
4749
  /**
3692
4750
  * Internal server error
3693
4751
  */
@@ -4047,16 +5105,46 @@ export type TriggerReindexResponses = {
4047
5105
 
4048
5106
  export type TriggerReindexResponse = TriggerReindexResponses[keyof TriggerReindexResponses];
4049
5107
 
4050
- export type TriggerSearchReindexData = {
4051
- body?: never;
4052
- path?: never;
5108
+ export type RescanForInventoryData = {
5109
+ /**
5110
+ * Optional; empty body uses defaults
5111
+ */
5112
+ body: RescanForInventoryRequest;
5113
+ path?: never;
5114
+ query?: never;
5115
+ url: '/api/v1/admin/rescan-for-inventory';
5116
+ };
5117
+
5118
+ export type RescanForInventoryErrors = {
5119
+ /**
5120
+ * Admin privileges required
5121
+ */
5122
+ 403: unknown;
5123
+ /**
5124
+ * Scanner service not configured
5125
+ */
5126
+ 503: unknown;
5127
+ };
5128
+
5129
+ export type RescanForInventoryResponses = {
5130
+ /**
5131
+ * Rescans enqueued
5132
+ */
5133
+ 200: RescanForInventoryResponse;
5134
+ };
5135
+
5136
+ export type RescanForInventoryResponse2 = RescanForInventoryResponses[keyof RescanForInventoryResponses];
5137
+
5138
+ export type TriggerSearchReindexData = {
5139
+ body?: never;
5140
+ path?: never;
4053
5141
  query?: never;
4054
5142
  url: '/api/v1/admin/search/reindex';
4055
5143
  };
4056
5144
 
4057
5145
  export type TriggerSearchReindexErrors = {
4058
5146
  /**
4059
- * Meilisearch is not configured
5147
+ * Search engine is not configured
4060
5148
  */
4061
5149
  500: unknown;
4062
5150
  };
@@ -4116,6 +5204,37 @@ export type UpdateSettingsResponses = {
4116
5204
 
4117
5205
  export type UpdateSettingsResponse = UpdateSettingsResponses[keyof UpdateSettingsResponses];
4118
5206
 
5207
+ export type SendTestEmailData = {
5208
+ body: SmtpTestRequest;
5209
+ path?: never;
5210
+ query?: never;
5211
+ url: '/api/v1/admin/smtp/test';
5212
+ };
5213
+
5214
+ export type SendTestEmailErrors = {
5215
+ /**
5216
+ * Invalid request (e.g. bad email address)
5217
+ */
5218
+ 400: unknown;
5219
+ /**
5220
+ * Admin privileges required
5221
+ */
5222
+ 403: unknown;
5223
+ /**
5224
+ * SMTP not configured
5225
+ */
5226
+ 503: unknown;
5227
+ };
5228
+
5229
+ export type SendTestEmailResponses = {
5230
+ /**
5231
+ * Test email sent successfully
5232
+ */
5233
+ 200: SmtpTestResponse;
5234
+ };
5235
+
5236
+ export type SendTestEmailResponse = SendTestEmailResponses[keyof SendTestEmailResponses];
5237
+
4119
5238
  export type ListLdapData = {
4120
5239
  body?: never;
4121
5240
  path?: never;
@@ -4783,6 +5902,28 @@ export type RunStorageGcResponses = {
4783
5902
 
4784
5903
  export type RunStorageGcResponse = RunStorageGcResponses[keyof RunStorageGcResponses];
4785
5904
 
5905
+ export type OciBlobReportData = {
5906
+ body?: never;
5907
+ path?: never;
5908
+ query?: {
5909
+ /**
5910
+ * Grace window in hours used to compute the `aged_*` figures. Defaults
5911
+ * to 24h; non-positive or out-of-range values are clamped server-side.
5912
+ */
5913
+ grace_hours?: number | null;
5914
+ };
5915
+ url: '/api/v1/admin/storage-gc/oci-blob-report';
5916
+ };
5917
+
5918
+ export type OciBlobReportResponses = {
5919
+ /**
5920
+ * OCI blob footprint report
5921
+ */
5922
+ 200: OciBlobFootprintReport;
5923
+ };
5924
+
5925
+ export type OciBlobReportResponse = OciBlobReportResponses[keyof OciBlobReportResponses];
5926
+
4786
5927
  export type ListCrashesData = {
4787
5928
  body?: never;
4788
5929
  path?: never;
@@ -5343,7 +6484,7 @@ export type LoginResponses = {
5343
6484
  export type LoginResponse2 = LoginResponses[keyof LoginResponses];
5344
6485
 
5345
6486
  export type LogoutData = {
5346
- body?: never;
6487
+ body?: RefreshTokenRequest;
5347
6488
  path?: never;
5348
6489
  query?: never;
5349
6490
  url: '/api/v1/auth/logout';
@@ -5475,9 +6616,12 @@ export type OidcCallbackData = {
5475
6616
  */
5476
6617
  id: string;
5477
6618
  };
5478
- query: {
5479
- code: string;
5480
- state: string;
6619
+ query?: {
6620
+ code?: string | null;
6621
+ state?: string | null;
6622
+ error?: string | null;
6623
+ error_description?: string | null;
6624
+ error_uri?: string | null;
5481
6625
  };
5482
6626
  url: '/api/v1/auth/sso/oidc/{id}/callback';
5483
6627
  };
@@ -5487,6 +6631,10 @@ export type OidcCallbackErrors = {
5487
6631
  * Invalid callback parameters
5488
6632
  */
5489
6633
  400: ErrorResponse;
6634
+ /**
6635
+ * IdP error or invalid/expired SSO state
6636
+ */
6637
+ 401: ErrorResponse;
5490
6638
  };
5491
6639
 
5492
6640
  export type OidcCallbackError = OidcCallbackErrors[keyof OidcCallbackErrors];
@@ -5578,6 +6726,10 @@ export type CreateDownloadTicketData = {
5578
6726
  };
5579
6727
 
5580
6728
  export type CreateDownloadTicketErrors = {
6729
+ /**
6730
+ * Invalid resource_path
6731
+ */
6732
+ 400: ErrorResponse;
5581
6733
  /**
5582
6734
  * Not authenticated
5583
6735
  */
@@ -6430,6 +7582,10 @@ export type ListGroupsData = {
6430
7582
  };
6431
7583
 
6432
7584
  export type ListGroupsErrors = {
7585
+ /**
7586
+ * Authentication required
7587
+ */
7588
+ 401: unknown;
6433
7589
  /**
6434
7590
  * Internal server error
6435
7591
  */
@@ -6453,6 +7609,14 @@ export type CreateGroupData = {
6453
7609
  };
6454
7610
 
6455
7611
  export type CreateGroupErrors = {
7612
+ /**
7613
+ * Authentication required
7614
+ */
7615
+ 401: unknown;
7616
+ /**
7617
+ * Insufficient permissions
7618
+ */
7619
+ 403: unknown;
6456
7620
  /**
6457
7621
  * Group name already exists
6458
7622
  */
@@ -6485,6 +7649,14 @@ export type DeleteGroupData = {
6485
7649
  };
6486
7650
 
6487
7651
  export type DeleteGroupErrors = {
7652
+ /**
7653
+ * Authentication required
7654
+ */
7655
+ 401: unknown;
7656
+ /**
7657
+ * Insufficient permissions
7658
+ */
7659
+ 403: unknown;
6488
7660
  /**
6489
7661
  * Group not found
6490
7662
  */
@@ -6510,11 +7682,24 @@ export type GetGroupData = {
6510
7682
  */
6511
7683
  id: string;
6512
7684
  };
6513
- query?: never;
7685
+ query?: {
7686
+ /**
7687
+ * Maximum number of members to return (default: 50, max: 200)
7688
+ */
7689
+ member_limit?: number | null;
7690
+ /**
7691
+ * Number of members to skip for pagination (default: 0)
7692
+ */
7693
+ member_offset?: number | null;
7694
+ };
6514
7695
  url: '/api/v1/groups/{id}';
6515
7696
  };
6516
7697
 
6517
7698
  export type GetGroupErrors = {
7699
+ /**
7700
+ * Authentication required
7701
+ */
7702
+ 401: unknown;
6518
7703
  /**
6519
7704
  * Group not found
6520
7705
  */
@@ -6527,9 +7712,9 @@ export type GetGroupErrors = {
6527
7712
 
6528
7713
  export type GetGroupResponses = {
6529
7714
  /**
6530
- * Group details
7715
+ * Group details with paginated members
6531
7716
  */
6532
- 200: GroupResponse;
7717
+ 200: GroupDetailResponse;
6533
7718
  };
6534
7719
 
6535
7720
  export type GetGroupResponse = GetGroupResponses[keyof GetGroupResponses];
@@ -6547,6 +7732,14 @@ export type UpdateGroupData = {
6547
7732
  };
6548
7733
 
6549
7734
  export type UpdateGroupErrors = {
7735
+ /**
7736
+ * Authentication required
7737
+ */
7738
+ 401: unknown;
7739
+ /**
7740
+ * Insufficient permissions
7741
+ */
7742
+ 403: unknown;
6550
7743
  /**
6551
7744
  * Group not found
6552
7745
  */
@@ -6579,6 +7772,14 @@ export type RemoveMembersData = {
6579
7772
  };
6580
7773
 
6581
7774
  export type RemoveMembersErrors = {
7775
+ /**
7776
+ * Authentication required
7777
+ */
7778
+ 401: unknown;
7779
+ /**
7780
+ * Insufficient permissions
7781
+ */
7782
+ 403: unknown;
6582
7783
  /**
6583
7784
  * Group not found
6584
7785
  */
@@ -6609,6 +7810,14 @@ export type AddMembersData = {
6609
7810
  };
6610
7811
 
6611
7812
  export type AddMembersErrors = {
7813
+ /**
7814
+ * Authentication required
7815
+ */
7816
+ 401: unknown;
7817
+ /**
7818
+ * Insufficient permissions
7819
+ */
7820
+ 403: unknown;
6612
7821
  /**
6613
7822
  * Group not found
6614
7823
  */
@@ -8076,6 +9285,78 @@ export type UnassignRepoResponses = {
8076
9285
  200: unknown;
8077
9286
  };
8078
9287
 
9288
+ export type GetSubscriptionData = {
9289
+ body?: never;
9290
+ path: {
9291
+ /**
9292
+ * Peer instance ID
9293
+ */
9294
+ id: string;
9295
+ /**
9296
+ * Repository ID
9297
+ */
9298
+ repo_id: string;
9299
+ };
9300
+ query?: never;
9301
+ url: '/api/v1/peers/{id}/repositories/{repo_id}';
9302
+ };
9303
+
9304
+ export type GetSubscriptionErrors = {
9305
+ /**
9306
+ * Subscription not found
9307
+ */
9308
+ 404: unknown;
9309
+ /**
9310
+ * Internal server error
9311
+ */
9312
+ 500: unknown;
9313
+ };
9314
+
9315
+ export type GetSubscriptionResponses = {
9316
+ /**
9317
+ * Subscription details
9318
+ */
9319
+ 200: SubscriptionResponse;
9320
+ };
9321
+
9322
+ export type GetSubscriptionResponse = GetSubscriptionResponses[keyof GetSubscriptionResponses];
9323
+
9324
+ export type RunSubscriptionNowData = {
9325
+ body?: never;
9326
+ path: {
9327
+ /**
9328
+ * Peer instance ID
9329
+ */
9330
+ id: string;
9331
+ /**
9332
+ * Repository ID
9333
+ */
9334
+ repo_id: string;
9335
+ };
9336
+ query?: never;
9337
+ url: '/api/v1/peers/{id}/repositories/{repo_id}/sync';
9338
+ };
9339
+
9340
+ export type RunSubscriptionNowErrors = {
9341
+ /**
9342
+ * Subscription not found
9343
+ */
9344
+ 404: unknown;
9345
+ /**
9346
+ * Internal server error
9347
+ */
9348
+ 500: unknown;
9349
+ };
9350
+
9351
+ export type RunSubscriptionNowResponses = {
9352
+ /**
9353
+ * Sync tasks queued
9354
+ */
9355
+ 202: RunNowResponse;
9356
+ };
9357
+
9358
+ export type RunSubscriptionNowResponse = RunSubscriptionNowResponses[keyof RunSubscriptionNowResponses];
9359
+
8079
9360
  export type TriggerSyncData = {
8080
9361
  body?: never;
8081
9362
  path: {
@@ -9145,6 +10426,74 @@ export type PromotionHistoryResponses = {
9145
10426
 
9146
10427
  export type PromotionHistoryResponse2 = PromotionHistoryResponses[keyof PromotionHistoryResponses];
9147
10428
 
10429
+ export type GetReleaseTargetData = {
10430
+ body?: never;
10431
+ path: {
10432
+ /**
10433
+ * Staging repository key
10434
+ */
10435
+ key: string;
10436
+ };
10437
+ query?: never;
10438
+ url: '/api/v1/promotion/repositories/{key}/release-target';
10439
+ };
10440
+
10441
+ export type GetReleaseTargetErrors = {
10442
+ /**
10443
+ * Repository not found
10444
+ */
10445
+ 404: ErrorResponse;
10446
+ /**
10447
+ * Repository is not a staging repository
10448
+ */
10449
+ 422: ErrorResponse;
10450
+ };
10451
+
10452
+ export type GetReleaseTargetError = GetReleaseTargetErrors[keyof GetReleaseTargetErrors];
10453
+
10454
+ export type GetReleaseTargetResponses = {
10455
+ /**
10456
+ * Release target information
10457
+ */
10458
+ 200: ReleaseTargetResponse;
10459
+ };
10460
+
10461
+ export type GetReleaseTargetResponse = GetReleaseTargetResponses[keyof GetReleaseTargetResponses];
10462
+
10463
+ export type SetReleaseTargetData = {
10464
+ body: SetReleaseTargetRequest;
10465
+ path: {
10466
+ /**
10467
+ * Staging repository key
10468
+ */
10469
+ key: string;
10470
+ };
10471
+ query?: never;
10472
+ url: '/api/v1/promotion/repositories/{key}/release-target';
10473
+ };
10474
+
10475
+ export type SetReleaseTargetErrors = {
10476
+ /**
10477
+ * Repository not found
10478
+ */
10479
+ 404: ErrorResponse;
10480
+ /**
10481
+ * Validation error
10482
+ */
10483
+ 422: ErrorResponse;
10484
+ };
10485
+
10486
+ export type SetReleaseTargetError = SetReleaseTargetErrors[keyof SetReleaseTargetErrors];
10487
+
10488
+ export type SetReleaseTargetResponses = {
10489
+ /**
10490
+ * Release target updated
10491
+ */
10492
+ 200: ReleaseTargetResponse;
10493
+ };
10494
+
10495
+ export type SetReleaseTargetResponse = SetReleaseTargetResponses[keyof SetReleaseTargetResponses];
10496
+
9148
10497
  export type ListChecksData = {
9149
10498
  body?: never;
9150
10499
  path?: never;
@@ -9550,47 +10899,163 @@ export type SuppressIssueResponses = {
9550
10899
 
9551
10900
  export type SuppressIssueResponse = SuppressIssueResponses[keyof SuppressIssueResponses];
9552
10901
 
9553
- export type ListRepositoriesData = {
10902
+ export type GetQuarantineStatusData = {
9554
10903
  body?: never;
9555
- path?: never;
9556
- query?: {
9557
- page?: number | null;
9558
- per_page?: number | null;
9559
- format?: string | null;
9560
- type?: string | null;
9561
- q?: string | null;
10904
+ path: {
10905
+ /**
10906
+ * Artifact ID
10907
+ */
10908
+ artifact_id: string;
9562
10909
  };
9563
- url: '/api/v1/repositories';
9564
- };
9565
-
9566
- export type ListRepositoriesResponses = {
9567
- /**
9568
- * List of repositories
9569
- */
9570
- 200: RepositoryListResponse;
9571
- };
9572
-
9573
- export type ListRepositoriesResponse = ListRepositoriesResponses[keyof ListRepositoriesResponses];
9574
-
9575
- export type CreateRepositoryData = {
9576
- body: CreateRepositoryRequest;
9577
- path?: never;
9578
10910
  query?: never;
9579
- url: '/api/v1/repositories';
10911
+ url: '/api/v1/quarantine/{artifact_id}';
9580
10912
  };
9581
10913
 
9582
- export type CreateRepositoryErrors = {
10914
+ export type GetQuarantineStatusErrors = {
9583
10915
  /**
9584
10916
  * Authentication required
9585
10917
  */
9586
10918
  401: unknown;
9587
10919
  /**
9588
- * Repository key already exists
10920
+ * Artifact not found
9589
10921
  */
9590
- 409: unknown;
10922
+ 404: unknown;
9591
10923
  };
9592
10924
 
9593
- export type CreateRepositoryResponses = {
10925
+ export type GetQuarantineStatusResponses = {
10926
+ /**
10927
+ * Quarantine status
10928
+ */
10929
+ 200: QuarantineStatusResponse;
10930
+ };
10931
+
10932
+ export type GetQuarantineStatusResponse = GetQuarantineStatusResponses[keyof GetQuarantineStatusResponses];
10933
+
10934
+ export type RejectQuarantinedArtifactData = {
10935
+ body: RejectRequest;
10936
+ path: {
10937
+ /**
10938
+ * Artifact ID
10939
+ */
10940
+ artifact_id: string;
10941
+ };
10942
+ query?: never;
10943
+ url: '/api/v1/quarantine/{artifact_id}/reject';
10944
+ };
10945
+
10946
+ export type RejectQuarantinedArtifactErrors = {
10947
+ /**
10948
+ * Authentication required
10949
+ */
10950
+ 401: unknown;
10951
+ /**
10952
+ * Admin access required
10953
+ */
10954
+ 403: unknown;
10955
+ /**
10956
+ * Artifact not found
10957
+ */
10958
+ 404: unknown;
10959
+ /**
10960
+ * Artifact is not in quarantined state
10961
+ */
10962
+ 409: unknown;
10963
+ };
10964
+
10965
+ export type RejectQuarantinedArtifactResponses = {
10966
+ /**
10967
+ * Artifact rejected
10968
+ */
10969
+ 200: QuarantineActionResponse;
10970
+ };
10971
+
10972
+ export type RejectQuarantinedArtifactResponse = RejectQuarantinedArtifactResponses[keyof RejectQuarantinedArtifactResponses];
10973
+
10974
+ export type ReleaseArtifactData = {
10975
+ body?: never;
10976
+ path: {
10977
+ /**
10978
+ * Artifact ID
10979
+ */
10980
+ artifact_id: string;
10981
+ };
10982
+ query?: never;
10983
+ url: '/api/v1/quarantine/{artifact_id}/release';
10984
+ };
10985
+
10986
+ export type ReleaseArtifactErrors = {
10987
+ /**
10988
+ * Authentication required
10989
+ */
10990
+ 401: unknown;
10991
+ /**
10992
+ * Admin access required
10993
+ */
10994
+ 403: unknown;
10995
+ /**
10996
+ * Artifact not found
10997
+ */
10998
+ 404: unknown;
10999
+ /**
11000
+ * Artifact is not in quarantined state
11001
+ */
11002
+ 409: unknown;
11003
+ };
11004
+
11005
+ export type ReleaseArtifactResponses = {
11006
+ /**
11007
+ * Artifact released
11008
+ */
11009
+ 200: QuarantineActionResponse;
11010
+ };
11011
+
11012
+ export type ReleaseArtifactResponse = ReleaseArtifactResponses[keyof ReleaseArtifactResponses];
11013
+
11014
+ export type ListRepositoriesData = {
11015
+ body?: never;
11016
+ path?: never;
11017
+ query?: {
11018
+ page?: number | null;
11019
+ per_page?: number | null;
11020
+ format?: string | null;
11021
+ type?: string | null;
11022
+ q?: string | null;
11023
+ };
11024
+ url: '/api/v1/repositories';
11025
+ };
11026
+
11027
+ export type ListRepositoriesResponses = {
11028
+ /**
11029
+ * List of repositories
11030
+ */
11031
+ 200: RepositoryListResponse;
11032
+ };
11033
+
11034
+ export type ListRepositoriesResponse = ListRepositoriesResponses[keyof ListRepositoriesResponses];
11035
+
11036
+ export type CreateRepositoryData = {
11037
+ body: CreateRepositoryRequest;
11038
+ path?: never;
11039
+ query?: never;
11040
+ url: '/api/v1/repositories';
11041
+ };
11042
+
11043
+ export type CreateRepositoryErrors = {
11044
+ /**
11045
+ * Authentication required
11046
+ */
11047
+ 401: unknown;
11048
+ /**
11049
+ * Insufficient permissions
11050
+ */
11051
+ 403: unknown;
11052
+ /**
11053
+ * Repository key already exists
11054
+ */
11055
+ 409: unknown;
11056
+ };
11057
+
11058
+ export type CreateRepositoryResponses = {
9594
11059
  /**
9595
11060
  * Repository created
9596
11061
  */
@@ -9616,6 +11081,10 @@ export type DeleteRepositoryErrors = {
9616
11081
  * Authentication required
9617
11082
  */
9618
11083
  401: unknown;
11084
+ /**
11085
+ * Insufficient permissions
11086
+ */
11087
+ 403: unknown;
9619
11088
  /**
9620
11089
  * Repository not found
9621
11090
  */
@@ -9674,6 +11143,10 @@ export type UpdateRepositoryErrors = {
9674
11143
  * Authentication required
9675
11144
  */
9676
11145
  401: unknown;
11146
+ /**
11147
+ * Insufficient permissions
11148
+ */
11149
+ 403: unknown;
9677
11150
  /**
9678
11151
  * Repository not found
9679
11152
  */
@@ -9706,6 +11179,19 @@ export type ListArtifactsData = {
9706
11179
  per_page?: number | null;
9707
11180
  q?: string | null;
9708
11181
  path_prefix?: string | null;
11182
+ /**
11183
+ * Server-side artifact grouping.
11184
+ *
11185
+ * Supported values:
11186
+ * - `maven_component`: Maven/Gradle artifacts are grouped by
11187
+ * groupId, artifactId, and version. Individual files (jar, pom,
11188
+ * checksums) appear in the `artifact_files` array of each component.
11189
+ * - `docker_tag`: Docker/OCI artifacts are grouped by (image, tag),
11190
+ * with `total_size_bytes` summed across the manifest config and
11191
+ * referenced layer blobs. The grouped rows are returned in the
11192
+ * `docker_tags` array.
11193
+ */
11194
+ group_by?: string | null;
9709
11195
  };
9710
11196
  url: '/api/v1/repositories/{key}/artifacts';
9711
11197
  };
@@ -9751,6 +11237,10 @@ export type DeleteArtifactErrors = {
9751
11237
  * Artifact not found
9752
11238
  */
9753
11239
  404: unknown;
11240
+ /**
11241
+ * Artifact is immutable (released) and cannot be deleted
11242
+ */
11243
+ 409: unknown;
9754
11244
  };
9755
11245
 
9756
11246
  export type DeleteArtifactResponses = {
@@ -9892,6 +11382,55 @@ export type SetCacheTtlResponses = {
9892
11382
 
9893
11383
  export type SetCacheTtlResponse = SetCacheTtlResponses[keyof SetCacheTtlResponses];
9894
11384
 
11385
+ export type InvalidateCacheData = {
11386
+ body?: never;
11387
+ path: {
11388
+ /**
11389
+ * Repository key
11390
+ */
11391
+ key: string;
11392
+ };
11393
+ query: {
11394
+ /**
11395
+ * Artifact path to evict from the proxy cache. Same shape as the path
11396
+ * segment of `GET /api/v1/repositories/{key}/artifacts/{path}`.
11397
+ * Path-traversal segments such as `..` are rejected by
11398
+ * `ProxyService::cache_storage_key` (covered by
11399
+ * `test_invalidate_cache_by_key_rejects_invalid_path`).
11400
+ */
11401
+ path: string;
11402
+ };
11403
+ url: '/api/v1/repositories/{key}/cache/invalidate';
11404
+ };
11405
+
11406
+ export type InvalidateCacheErrors = {
11407
+ /**
11408
+ * Validation error (e.g. non-remote repo or invalid path)
11409
+ */
11410
+ 400: unknown;
11411
+ /**
11412
+ * Authentication required
11413
+ */
11414
+ 401: unknown;
11415
+ /**
11416
+ * Repository not found
11417
+ */
11418
+ 404: unknown;
11419
+ /**
11420
+ * Proxy service not configured on this deployment
11421
+ */
11422
+ 503: unknown;
11423
+ };
11424
+
11425
+ export type InvalidateCacheResponses = {
11426
+ /**
11427
+ * Cache entry invalidated (or was already absent)
11428
+ */
11429
+ 200: InvalidateCacheResponse;
11430
+ };
11431
+
11432
+ export type InvalidateCacheResponse2 = InvalidateCacheResponses[keyof InvalidateCacheResponses];
11433
+
9895
11434
  export type DownloadArtifactData = {
9896
11435
  body?: never;
9897
11436
  path: {
@@ -9924,6 +11463,122 @@ export type DownloadArtifactResponses = {
9924
11463
 
9925
11464
  export type DownloadArtifactResponse = DownloadArtifactResponses[keyof DownloadArtifactResponses];
9926
11465
 
11466
+ export type ListSubscriptionsData = {
11467
+ body?: never;
11468
+ path: {
11469
+ /**
11470
+ * Repository key
11471
+ */
11472
+ key: string;
11473
+ };
11474
+ query?: never;
11475
+ url: '/api/v1/repositories/{key}/email-subscriptions';
11476
+ };
11477
+
11478
+ export type ListSubscriptionsErrors = {
11479
+ /**
11480
+ * Not authenticated
11481
+ */
11482
+ 401: unknown;
11483
+ /**
11484
+ * Insufficient permissions
11485
+ */
11486
+ 403: unknown;
11487
+ /**
11488
+ * Repository not found
11489
+ */
11490
+ 404: unknown;
11491
+ };
11492
+
11493
+ export type ListSubscriptionsResponses = {
11494
+ /**
11495
+ * List of email subscriptions
11496
+ */
11497
+ 200: EmailSubscriptionListResponse;
11498
+ };
11499
+
11500
+ export type ListSubscriptionsResponse = ListSubscriptionsResponses[keyof ListSubscriptionsResponses];
11501
+
11502
+ export type CreateSubscriptionData = {
11503
+ body: CreateEmailSubscriptionRequest;
11504
+ path: {
11505
+ /**
11506
+ * Repository key
11507
+ */
11508
+ key: string;
11509
+ };
11510
+ query?: never;
11511
+ url: '/api/v1/repositories/{key}/email-subscriptions';
11512
+ };
11513
+
11514
+ export type CreateSubscriptionErrors = {
11515
+ /**
11516
+ * Validation error
11517
+ */
11518
+ 400: unknown;
11519
+ /**
11520
+ * Not authenticated
11521
+ */
11522
+ 401: unknown;
11523
+ /**
11524
+ * Insufficient permissions
11525
+ */
11526
+ 403: unknown;
11527
+ /**
11528
+ * Repository not found
11529
+ */
11530
+ 404: unknown;
11531
+ };
11532
+
11533
+ export type CreateSubscriptionResponses = {
11534
+ /**
11535
+ * Subscription created
11536
+ */
11537
+ 201: EmailSubscriptionResponse;
11538
+ };
11539
+
11540
+ export type CreateSubscriptionResponse = CreateSubscriptionResponses[keyof CreateSubscriptionResponses];
11541
+
11542
+ export type DeleteSubscriptionData = {
11543
+ body?: never;
11544
+ path: {
11545
+ /**
11546
+ * Repository key
11547
+ */
11548
+ key: string;
11549
+ /**
11550
+ * Subscription ID
11551
+ */
11552
+ subscription_id: string;
11553
+ };
11554
+ query?: never;
11555
+ url: '/api/v1/repositories/{key}/email-subscriptions/{subscription_id}';
11556
+ };
11557
+
11558
+ export type DeleteSubscriptionErrors = {
11559
+ /**
11560
+ * Not authenticated
11561
+ */
11562
+ 401: unknown;
11563
+ /**
11564
+ * Insufficient permissions
11565
+ */
11566
+ 403: unknown;
11567
+ /**
11568
+ * Subscription or repository not found
11569
+ */
11570
+ 404: unknown;
11571
+ };
11572
+
11573
+ export type DeleteSubscriptionResponses = {
11574
+ /**
11575
+ * Subscription deleted
11576
+ */
11577
+ 204: void;
11578
+ };
11579
+
11580
+ export type DeleteSubscriptionResponse = DeleteSubscriptionResponses[keyof DeleteSubscriptionResponses];
11581
+
9927
11582
  export type ListRepoLabelsData = {
9928
11583
  body?: never;
9929
11584
  path: {
@@ -10061,6 +11716,10 @@ export type ListVirtualMembersErrors = {
10061
11716
  * Repository is not virtual
10062
11717
  */
10063
11718
  400: unknown;
11719
+ /**
11720
+ * Authentication required
11721
+ */
11722
+ 401: unknown;
10064
11723
  /**
10065
11724
  * Repository not found
10066
11725
  */
@@ -10069,7 +11728,7 @@ export type ListVirtualMembersErrors = {
10069
11728
 
10070
11729
  export type ListVirtualMembersResponses = {
10071
11730
  /**
10072
- * List of virtual repository members
11731
+ * List of virtual repository members (filtered to caller-visible members)
10073
11732
  */
10074
11733
  200: VirtualMembersListResponse;
10075
11734
  };
@@ -10097,6 +11756,10 @@ export type AddVirtualMemberErrors = {
10097
11756
  * Repository or member not found
10098
11757
  */
10099
11758
  404: unknown;
11759
+ /**
11760
+ * Member already exists in virtual repository
11761
+ */
11762
+ 409: unknown;
10100
11763
  };
10101
11764
 
10102
11765
  export type AddVirtualMemberResponses = {
@@ -10182,7 +11845,7 @@ export type RemoveVirtualMemberResponses = {
10182
11845
  200: unknown;
10183
11846
  };
10184
11847
 
10185
- export type GetRepoSecurityData = {
11848
+ export type ListPypiTracksData = {
10186
11849
  body?: never;
10187
11850
  path: {
10188
11851
  /**
@@ -10191,10 +11854,208 @@ export type GetRepoSecurityData = {
10191
11854
  key: string;
10192
11855
  };
10193
11856
  query?: never;
10194
- url: '/api/v1/repositories/{key}/security';
11857
+ url: '/api/v1/repositories/{key}/pypi-tracks';
10195
11858
  };
10196
11859
 
10197
- export type GetRepoSecurityErrors = {
11860
+ export type ListPypiTracksErrors = {
11861
+ /**
11862
+ * Repository not found
11863
+ */
11864
+ 404: unknown;
11865
+ };
11866
+
11867
+ export type ListPypiTracksResponses = {
11868
+ /**
11869
+ * tracks declarations
11870
+ */
11871
+ 200: PypiTracksListResponse;
11872
+ };
11873
+
11874
+ export type ListPypiTracksResponse = ListPypiTracksResponses[keyof ListPypiTracksResponses];
11875
+
11876
+ export type DeletePypiTrackData = {
11877
+ body?: never;
11878
+ path: {
11879
+ /**
11880
+ * Repository key
11881
+ */
11882
+ key: string;
11883
+ /**
11884
+ * Project name (PEP 503 normalized server-side)
11885
+ */
11886
+ project: string;
11887
+ };
11888
+ query?: never;
11889
+ url: '/api/v1/repositories/{key}/pypi-tracks/{project}';
11890
+ };
11891
+
11892
+ export type DeletePypiTrackErrors = {
11893
+ /**
11894
+ * Authentication required
11895
+ */
11896
+ 401: unknown;
11897
+ /**
11898
+ * Repository not found
11899
+ */
11900
+ 404: unknown;
11901
+ };
11902
+
11903
+ export type DeletePypiTrackResponses = {
11904
+ /**
11905
+ * tracks declaration removed (idempotent)
11906
+ */
11907
+ 204: void;
11908
+ };
11909
+
11910
+ export type DeletePypiTrackResponse = DeletePypiTrackResponses[keyof DeletePypiTrackResponses];
11911
+
11912
+ export type PutPypiTrackData = {
11913
+ body: PypiTrackRequest;
11914
+ path: {
11915
+ /**
11916
+ * Repository key
11917
+ */
11918
+ key: string;
11919
+ /**
11920
+ * Project name (PEP 503 normalized server-side)
11921
+ */
11922
+ project: string;
11923
+ };
11924
+ query?: never;
11925
+ url: '/api/v1/repositories/{key}/pypi-tracks/{project}';
11926
+ };
11927
+
11928
+ export type PutPypiTrackErrors = {
11929
+ /**
11930
+ * Invalid request or repository type
11931
+ */
11932
+ 400: unknown;
11933
+ /**
11934
+ * Authentication required
11935
+ */
11936
+ 401: unknown;
11937
+ /**
11938
+ * Repository not found
11939
+ */
11940
+ 404: unknown;
11941
+ };
11942
+
11943
+ export type PutPypiTrackResponses = {
11944
+ /**
11945
+ * tracks declaration stored
11946
+ */
11947
+ 200: PypiTrackResponse;
11948
+ };
11949
+
11950
+ export type PutPypiTrackResponse = PutPypiTrackResponses[keyof PutPypiTrackResponses];
11951
+
11952
+ export type DeleteRoutingRulesData = {
11953
+ body?: never;
11954
+ path: {
11955
+ /**
11956
+ * Repository key
11957
+ */
11958
+ key: string;
11959
+ };
11960
+ query?: never;
11961
+ url: '/api/v1/repositories/{key}/routing-rules';
11962
+ };
11963
+
11964
+ export type DeleteRoutingRulesErrors = {
11965
+ /**
11966
+ * Authentication required
11967
+ */
11968
+ 401: unknown;
11969
+ /**
11970
+ * Repository not found
11971
+ */
11972
+ 404: unknown;
11973
+ };
11974
+
11975
+ export type DeleteRoutingRulesResponses = {
11976
+ /**
11977
+ * Routing rules deleted
11978
+ */
11979
+ 200: unknown;
11980
+ };
11981
+
11982
+ export type GetRoutingRulesData = {
11983
+ body?: never;
11984
+ path: {
11985
+ /**
11986
+ * Repository key
11987
+ */
11988
+ key: string;
11989
+ };
11990
+ query?: never;
11991
+ url: '/api/v1/repositories/{key}/routing-rules';
11992
+ };
11993
+
11994
+ export type GetRoutingRulesErrors = {
11995
+ /**
11996
+ * Repository not found
11997
+ */
11998
+ 404: unknown;
11999
+ };
12000
+
12001
+ export type GetRoutingRulesResponses = {
12002
+ /**
12003
+ * Current routing rules
12004
+ */
12005
+ 200: RoutingRulesResponse;
12006
+ };
12007
+
12008
+ export type GetRoutingRulesResponse = GetRoutingRulesResponses[keyof GetRoutingRulesResponses];
12009
+
12010
+ export type SetRoutingRulesData = {
12011
+ body: SetRoutingRulesRequest;
12012
+ path: {
12013
+ /**
12014
+ * Repository key
12015
+ */
12016
+ key: string;
12017
+ };
12018
+ query?: never;
12019
+ url: '/api/v1/repositories/{key}/routing-rules';
12020
+ };
12021
+
12022
+ export type SetRoutingRulesErrors = {
12023
+ /**
12024
+ * Invalid rule (bad regex or capture reference)
12025
+ */
12026
+ 400: unknown;
12027
+ /**
12028
+ * Authentication required
12029
+ */
12030
+ 401: unknown;
12031
+ /**
12032
+ * Repository not found
12033
+ */
12034
+ 404: unknown;
12035
+ };
12036
+
12037
+ export type SetRoutingRulesResponses = {
12038
+ /**
12039
+ * Routing rules saved
12040
+ */
12041
+ 200: RoutingRulesResponse;
12042
+ };
12043
+
12044
+ export type SetRoutingRulesResponse = SetRoutingRulesResponses[keyof SetRoutingRulesResponses];
12045
+
12046
+ export type GetRepoSecurityData = {
12047
+ body?: never;
12048
+ path: {
12049
+ /**
12050
+ * Repository key
12051
+ */
12052
+ key: string;
12053
+ };
12054
+ query?: never;
12055
+ url: '/api/v1/repositories/{key}/security';
12056
+ };
12057
+
12058
+ export type GetRepoSecurityErrors = {
10198
12059
  /**
10199
12060
  * Repository not found
10200
12061
  */
@@ -10224,98 +12085,254 @@ export type UpdateRepoSecurityData = {
10224
12085
  url: '/api/v1/repositories/{key}/security';
10225
12086
  };
10226
12087
 
10227
- export type UpdateRepoSecurityErrors = {
12088
+ export type UpdateRepoSecurityErrors = {
12089
+ /**
12090
+ * Repository not found
12091
+ */
12092
+ 404: ErrorResponse;
12093
+ };
12094
+
12095
+ export type UpdateRepoSecurityError = UpdateRepoSecurityErrors[keyof UpdateRepoSecurityErrors];
12096
+
12097
+ export type UpdateRepoSecurityResponses = {
12098
+ /**
12099
+ * Repository security config updated
12100
+ */
12101
+ 200: ScanConfigResponse;
12102
+ };
12103
+
12104
+ export type UpdateRepoSecurityResponse = UpdateRepoSecurityResponses[keyof UpdateRepoSecurityResponses];
12105
+
12106
+ export type ListRepoScansData = {
12107
+ body?: never;
12108
+ path: {
12109
+ /**
12110
+ * Repository key
12111
+ */
12112
+ key: string;
12113
+ };
12114
+ query?: {
12115
+ repository_id?: string | null;
12116
+ artifact_id?: string | null;
12117
+ status?: string | null;
12118
+ page?: number | null;
12119
+ per_page?: number | null;
12120
+ };
12121
+ url: '/api/v1/repositories/{key}/security/scans';
12122
+ };
12123
+
12124
+ export type ListRepoScansErrors = {
12125
+ /**
12126
+ * Repository not found
12127
+ */
12128
+ 404: ErrorResponse;
12129
+ };
12130
+
12131
+ export type ListRepoScansError = ListRepoScansErrors[keyof ListRepoScansErrors];
12132
+
12133
+ export type ListRepoScansResponses = {
12134
+ /**
12135
+ * Paginated list of scans for a repository
12136
+ */
12137
+ 200: ScanListResponse;
12138
+ };
12139
+
12140
+ export type ListRepoScansResponse = ListRepoScansResponses[keyof ListRepoScansResponses];
12141
+
12142
+ export type TestUpstreamData = {
12143
+ body?: never;
12144
+ path: {
12145
+ /**
12146
+ * Repository key
12147
+ */
12148
+ key: string;
12149
+ };
12150
+ query?: never;
12151
+ url: '/api/v1/repositories/{key}/test-upstream';
12152
+ };
12153
+
12154
+ export type TestUpstreamErrors = {
12155
+ /**
12156
+ * Repository is not remote or has no upstream URL
12157
+ */
12158
+ 400: unknown;
12159
+ /**
12160
+ * Authentication required
12161
+ */
12162
+ 401: unknown;
12163
+ /**
12164
+ * Repository not found
12165
+ */
12166
+ 404: unknown;
12167
+ /**
12168
+ * Upstream unreachable
12169
+ */
12170
+ 502: unknown;
12171
+ };
12172
+
12173
+ export type TestUpstreamResponses = {
12174
+ /**
12175
+ * Upstream reachable
12176
+ */
12177
+ 200: unknown;
12178
+ };
12179
+
12180
+ export type ListRepoTokensData = {
12181
+ body?: never;
12182
+ path: {
12183
+ /**
12184
+ * Repository key
12185
+ */
12186
+ key: string;
12187
+ };
12188
+ query?: never;
12189
+ url: '/api/v1/repositories/{key}/tokens';
12190
+ };
12191
+
12192
+ export type ListRepoTokensErrors = {
12193
+ /**
12194
+ * Not authenticated
12195
+ */
12196
+ 401: unknown;
12197
+ /**
12198
+ * Insufficient permissions
12199
+ */
12200
+ 403: unknown;
12201
+ /**
12202
+ * Repository not found
12203
+ */
12204
+ 404: unknown;
12205
+ };
12206
+
12207
+ export type ListRepoTokensResponses = {
12208
+ /**
12209
+ * List of tokens on this repository
12210
+ */
12211
+ 200: RepoTokenListResponse;
12212
+ };
12213
+
12214
+ export type ListRepoTokensResponse = ListRepoTokensResponses[keyof ListRepoTokensResponses];
12215
+
12216
+ export type CreateRepoTokenData = {
12217
+ body: CreateRepoTokenRequest;
12218
+ path: {
12219
+ /**
12220
+ * Repository key
12221
+ */
12222
+ key: string;
12223
+ };
12224
+ query?: never;
12225
+ url: '/api/v1/repositories/{key}/tokens';
12226
+ };
12227
+
12228
+ export type CreateRepoTokenErrors = {
12229
+ /**
12230
+ * Validation error
12231
+ */
12232
+ 400: unknown;
12233
+ /**
12234
+ * Not authenticated
12235
+ */
12236
+ 401: unknown;
12237
+ /**
12238
+ * Insufficient permissions
12239
+ */
12240
+ 403: unknown;
10228
12241
  /**
10229
12242
  * Repository not found
10230
12243
  */
10231
- 404: ErrorResponse;
12244
+ 404: unknown;
10232
12245
  };
10233
12246
 
10234
- export type UpdateRepoSecurityError = UpdateRepoSecurityErrors[keyof UpdateRepoSecurityErrors];
10235
-
10236
- export type UpdateRepoSecurityResponses = {
12247
+ export type CreateRepoTokenResponses = {
10237
12248
  /**
10238
- * Repository security config updated
12249
+ * Token created (value shown once)
10239
12250
  */
10240
- 200: ScanConfigResponse;
12251
+ 200: CreateRepoTokenResponse;
10241
12252
  };
10242
12253
 
10243
- export type UpdateRepoSecurityResponse = UpdateRepoSecurityResponses[keyof UpdateRepoSecurityResponses];
12254
+ export type CreateRepoTokenResponse2 = CreateRepoTokenResponses[keyof CreateRepoTokenResponses];
10244
12255
 
10245
- export type ListRepoScansData = {
12256
+ export type RevokeRepoTokenData = {
10246
12257
  body?: never;
10247
12258
  path: {
10248
12259
  /**
10249
12260
  * Repository key
10250
12261
  */
10251
12262
  key: string;
12263
+ /**
12264
+ * Token ID
12265
+ */
12266
+ token_id: string;
10252
12267
  };
10253
- query?: {
10254
- repository_id?: string | null;
10255
- artifact_id?: string | null;
10256
- status?: string | null;
10257
- page?: number | null;
10258
- per_page?: number | null;
10259
- };
10260
- url: '/api/v1/repositories/{key}/security/scans';
12268
+ query?: never;
12269
+ url: '/api/v1/repositories/{key}/tokens/{token_id}';
10261
12270
  };
10262
12271
 
10263
- export type ListRepoScansErrors = {
12272
+ export type RevokeRepoTokenErrors = {
10264
12273
  /**
10265
- * Repository not found
12274
+ * Not authenticated
10266
12275
  */
10267
- 404: ErrorResponse;
12276
+ 401: unknown;
12277
+ /**
12278
+ * Insufficient permissions
12279
+ */
12280
+ 403: unknown;
12281
+ /**
12282
+ * Repository or token not found
12283
+ */
12284
+ 404: unknown;
10268
12285
  };
10269
12286
 
10270
- export type ListRepoScansError = ListRepoScansErrors[keyof ListRepoScansErrors];
10271
-
10272
- export type ListRepoScansResponses = {
12287
+ export type RevokeRepoTokenResponses = {
10273
12288
  /**
10274
- * Paginated list of scans for a repository
12289
+ * Token revoked
10275
12290
  */
10276
- 200: ScanListResponse;
12291
+ 204: void;
10277
12292
  };
10278
12293
 
10279
- export type ListRepoScansResponse = ListRepoScansResponses[keyof ListRepoScansResponses];
12294
+ export type RevokeRepoTokenResponse = RevokeRepoTokenResponses[keyof RevokeRepoTokenResponses];
10280
12295
 
10281
- export type TestUpstreamData = {
12296
+ export type GetRepoTokenData = {
10282
12297
  body?: never;
10283
12298
  path: {
10284
12299
  /**
10285
12300
  * Repository key
10286
12301
  */
10287
12302
  key: string;
12303
+ /**
12304
+ * Token ID
12305
+ */
12306
+ token_id: string;
10288
12307
  };
10289
12308
  query?: never;
10290
- url: '/api/v1/repositories/{key}/test-upstream';
12309
+ url: '/api/v1/repositories/{key}/tokens/{token_id}';
10291
12310
  };
10292
12311
 
10293
- export type TestUpstreamErrors = {
10294
- /**
10295
- * Repository is not remote or has no upstream URL
10296
- */
10297
- 400: unknown;
12312
+ export type GetRepoTokenErrors = {
10298
12313
  /**
10299
- * Authentication required
12314
+ * Not authenticated
10300
12315
  */
10301
12316
  401: unknown;
10302
12317
  /**
10303
- * Repository not found
12318
+ * Insufficient permissions
10304
12319
  */
10305
- 404: unknown;
12320
+ 403: unknown;
10306
12321
  /**
10307
- * Upstream unreachable
12322
+ * Repository or token not found
10308
12323
  */
10309
- 502: unknown;
12324
+ 404: unknown;
10310
12325
  };
10311
12326
 
10312
- export type TestUpstreamResponses = {
12327
+ export type GetRepoTokenResponses = {
10313
12328
  /**
10314
- * Upstream reachable
12329
+ * Token details
10315
12330
  */
10316
- 200: unknown;
12331
+ 200: RepoTokenResponse;
10317
12332
  };
10318
12333
 
12334
+ export type GetRepoTokenResponse = GetRepoTokenResponses[keyof GetRepoTokenResponses];
12335
+
10319
12336
  export type SetUpstreamAuthData = {
10320
12337
  body: UpstreamAuthRequest;
10321
12338
  path: {
@@ -10454,16 +12471,83 @@ export type CheckLicenseComplianceResponses = {
10454
12471
 
10455
12472
  export type CheckLicenseComplianceResponse = CheckLicenseComplianceResponses[keyof CheckLicenseComplianceResponses];
10456
12473
 
10457
- export type GetCveHistoryData = {
12474
+ export type GetCveHistoryByArtifactData = {
10458
12475
  body?: never;
10459
12476
  path: {
10460
12477
  /**
10461
- * Artifact ID
12478
+ * Artifact UUID
10462
12479
  */
10463
12480
  artifact_id: string;
10464
12481
  };
10465
12482
  query?: never;
10466
- url: '/api/v1/sbom/cve/history/{artifact_id}';
12483
+ url: '/api/v1/sbom/cve/history/by-artifact/{artifact_id}';
12484
+ };
12485
+
12486
+ export type GetCveHistoryByArtifactErrors = {
12487
+ /**
12488
+ * Caller does not have access to this artifact's repository
12489
+ */
12490
+ 403: unknown;
12491
+ /**
12492
+ * Artifact not found
12493
+ */
12494
+ 404: unknown;
12495
+ };
12496
+
12497
+ export type GetCveHistoryByArtifactResponses = {
12498
+ /**
12499
+ * CVE history entries
12500
+ */
12501
+ 200: Array<CveHistoryEntry>;
12502
+ };
12503
+
12504
+ export type GetCveHistoryByArtifactResponse = GetCveHistoryByArtifactResponses[keyof GetCveHistoryByArtifactResponses];
12505
+
12506
+ export type GetCveHistoryByCveData = {
12507
+ body?: never;
12508
+ path: {
12509
+ /**
12510
+ * CVE identifier (e.g. CVE-2019-10744)
12511
+ */
12512
+ cve_id: string;
12513
+ };
12514
+ query?: never;
12515
+ url: '/api/v1/sbom/cve/history/by-cve/{cve_id}';
12516
+ };
12517
+
12518
+ export type GetCveHistoryByCveErrors = {
12519
+ /**
12520
+ * Path id is not a valid CVE identifier
12521
+ */
12522
+ 400: unknown;
12523
+ };
12524
+
12525
+ export type GetCveHistoryByCveResponses = {
12526
+ /**
12527
+ * CVE history entries
12528
+ */
12529
+ 200: Array<CveHistoryEntry>;
12530
+ };
12531
+
12532
+ export type GetCveHistoryByCveResponse = GetCveHistoryByCveResponses[keyof GetCveHistoryByCveResponses];
12533
+
12534
+ export type GetCveHistoryData = {
12535
+ body?: never;
12536
+ path: {
12537
+ /**
12538
+ * 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}.
12539
+ */
12540
+ id: string;
12541
+ };
12542
+ query?: never;
12543
+ url: '/api/v1/sbom/cve/history/{id}';
12544
+ };
12545
+
12546
+ export type GetCveHistoryErrors = {
12547
+ /**
12548
+ * Path id is neither a valid UUID nor a valid CVE identifier
12549
+ */
12550
+ 400: unknown;
10467
12551
  };
10468
12552
 
10469
12553
  export type GetCveHistoryResponses = {
@@ -10475,6 +12559,48 @@ export type GetCveHistoryResponses = {
10475
12559
 
10476
12560
  export type GetCveHistoryResponse = GetCveHistoryResponses[keyof GetCveHistoryResponses];
10477
12561
 
12562
+ export type UpdateCveStatusByArtifactCveData = {
12563
+ body: UpdateCveStatusRequest;
12564
+ path: {
12565
+ /**
12566
+ * Artifact UUID
12567
+ */
12568
+ artifact_id: string;
12569
+ /**
12570
+ * CVE identifier (e.g. CVE-2019-10744)
12571
+ */
12572
+ cve_id: string;
12573
+ };
12574
+ query?: never;
12575
+ url: '/api/v1/sbom/cve/status/by-artifact/{artifact_id}/by-cve/{cve_id}';
12576
+ };
12577
+
12578
+ export type UpdateCveStatusByArtifactCveErrors = {
12579
+ /**
12580
+ * Validation error (e.g. invalid CVE id or unsupported status)
12581
+ */
12582
+ 400: ErrorResponse;
12583
+ /**
12584
+ * Caller does not have access to this artifact's repository
12585
+ */
12586
+ 403: unknown;
12587
+ /**
12588
+ * No scan_findings rows match (artifact_id, cve_id)
12589
+ */
12590
+ 404: unknown;
12591
+ };
12592
+
12593
+ export type UpdateCveStatusByArtifactCveError = UpdateCveStatusByArtifactCveErrors[keyof UpdateCveStatusByArtifactCveErrors];
12594
+
12595
+ export type UpdateCveStatusByArtifactCveResponses = {
12596
+ /**
12597
+ * Updated synth CVE entry
12598
+ */
12599
+ 200: CveHistoryEntry;
12600
+ };
12601
+
12602
+ export type UpdateCveStatusByArtifactCveResponse = UpdateCveStatusByArtifactCveResponses[keyof UpdateCveStatusByArtifactCveResponses];
12603
+
10478
12604
  export type UpdateCveStatusData = {
10479
12605
  body: UpdateCveStatusRequest;
10480
12606
  path: {
@@ -10746,9 +12872,9 @@ export type ConvertSbomError = ConvertSbomErrors[keyof ConvertSbomErrors];
10746
12872
 
10747
12873
  export type ConvertSbomResponses = {
10748
12874
  /**
10749
- * Converted SBOM
12875
+ * Converted SBOM with content
10750
12876
  */
10751
- 200: SbomResponse;
12877
+ 200: SbomContentResponse;
10752
12878
  };
10753
12879
 
10754
12880
  export type ConvertSbomResponse = ConvertSbomResponses[keyof ConvertSbomResponses];
@@ -10943,6 +13069,15 @@ export type GetDashboardData = {
10943
13069
  url: '/api/v1/security/dashboard';
10944
13070
  };
10945
13071
 
13072
+ export type GetDashboardErrors = {
13073
+ /**
13074
+ * Admin privileges required
13075
+ */
13076
+ 403: ErrorResponse;
13077
+ };
13078
+
13079
+ export type GetDashboardError = GetDashboardErrors[keyof GetDashboardErrors];
13080
+
10946
13081
  export type GetDashboardResponses = {
10947
13082
  /**
10948
13083
  * Security dashboard summary
@@ -10965,6 +13100,10 @@ export type RevokeAcknowledgmentData = {
10965
13100
  };
10966
13101
 
10967
13102
  export type RevokeAcknowledgmentErrors = {
13103
+ /**
13104
+ * Admin privileges required
13105
+ */
13106
+ 403: ErrorResponse;
10968
13107
  /**
10969
13108
  * Finding not found
10970
13109
  */
@@ -10995,6 +13134,10 @@ export type AcknowledgeFindingData = {
10995
13134
  };
10996
13135
 
10997
13136
  export type AcknowledgeFindingErrors = {
13137
+ /**
13138
+ * Admin privileges required
13139
+ */
13140
+ 403: ErrorResponse;
10998
13141
  /**
10999
13142
  * Finding not found
11000
13143
  */
@@ -11157,10 +13300,14 @@ export type TriggerScanErrors = {
11157
13300
  * Validation error
11158
13301
  */
11159
13302
  400: ErrorResponse;
13303
+ /**
13304
+ * bypass_dedup requested by non-admin caller
13305
+ */
13306
+ 403: ErrorResponse;
11160
13307
  /**
11161
13308
  * Scanner service not configured
11162
13309
  */
11163
- 500: ErrorResponse;
13310
+ 503: ErrorResponse;
11164
13311
  };
11165
13312
 
11166
13313
  export type TriggerScanError = TriggerScanErrors[keyof TriggerScanErrors];
@@ -11266,6 +13413,15 @@ export type GetAllScoresData = {
11266
13413
  url: '/api/v1/security/scores';
11267
13414
  };
11268
13415
 
13416
+ export type GetAllScoresErrors = {
13417
+ /**
13418
+ * Admin privileges required
13419
+ */
13420
+ 403: ErrorResponse;
13421
+ };
13422
+
13423
+ export type GetAllScoresError = GetAllScoresErrors[keyof GetAllScoresErrors];
13424
+
11269
13425
  export type GetAllScoresResponses = {
11270
13426
  /**
11271
13427
  * All repository security scores
@@ -12095,6 +14251,22 @@ export type TogglePolicyResponses = {
12095
14251
 
12096
14252
  export type TogglePolicyResponse = TogglePolicyResponses[keyof TogglePolicyResponses];
12097
14253
 
14254
+ export type GetSystemConfigData = {
14255
+ body?: never;
14256
+ path?: never;
14257
+ query?: never;
14258
+ url: '/api/v1/system/config';
14259
+ };
14260
+
14261
+ export type GetSystemConfigResponses = {
14262
+ /**
14263
+ * Public runtime configuration
14264
+ */
14265
+ 200: SystemConfigResponse;
14266
+ };
14267
+
14268
+ export type GetSystemConfigResponse = GetSystemConfigResponses[keyof GetSystemConfigResponses];
14269
+
12098
14270
  export type GetTreeData = {
12099
14271
  body?: never;
12100
14272
  path?: never;
@@ -12195,6 +14367,10 @@ export type CreateSessionErrors = {
12195
14367
  * Unauthorized
12196
14368
  */
12197
14369
  401: unknown;
14370
+ /**
14371
+ * Forbidden
14372
+ */
14373
+ 403: ErrorResponse;
12198
14374
  /**
12199
14375
  * Repository not found
12200
14376
  */
@@ -12495,6 +14671,42 @@ export type UpdateUserResponses = {
12495
14671
 
12496
14672
  export type UpdateUserResponse = UpdateUserResponses[keyof UpdateUserResponses];
12497
14673
 
14674
+ export type ForcePasswordChangeData = {
14675
+ body?: never;
14676
+ path: {
14677
+ /**
14678
+ * User ID
14679
+ */
14680
+ id: string;
14681
+ };
14682
+ query?: never;
14683
+ url: '/api/v1/users/{id}/force-password-change';
14684
+ };
14685
+
14686
+ export type ForcePasswordChangeErrors = {
14687
+ /**
14688
+ * Only administrators can force password changes
14689
+ */
14690
+ 403: unknown;
14691
+ /**
14692
+ * User not found
14693
+ */
14694
+ 404: unknown;
14695
+ /**
14696
+ * Cannot force password change for SSO users
14697
+ */
14698
+ 422: unknown;
14699
+ };
14700
+
14701
+ export type ForcePasswordChangeResponses = {
14702
+ /**
14703
+ * Flag set successfully
14704
+ */
14705
+ 200: ForcePasswordChangeResponse;
14706
+ };
14707
+
14708
+ export type ForcePasswordChangeResponse2 = ForcePasswordChangeResponses[keyof ForcePasswordChangeResponses];
14709
+
12498
14710
  export type ChangePasswordData = {
12499
14711
  body: ChangePasswordRequest;
12500
14712
  path: {
@@ -12769,13 +14981,17 @@ export type CreateWebhookErrors = {
12769
14981
  * Internal server error
12770
14982
  */
12771
14983
  500: unknown;
14984
+ /**
14985
+ * A secret was supplied but AK_WEBHOOK_SECRET_KEY is not configured, so the secret cannot be encrypted at rest
14986
+ */
14987
+ 503: unknown;
12772
14988
  };
12773
14989
 
12774
14990
  export type CreateWebhookResponses = {
12775
14991
  /**
12776
- * Webhook created successfully
14992
+ * Webhook created. Body includes the raw secret exactly once (omitted when created unsigned).
12777
14993
  */
12778
- 200: WebhookResponse;
14994
+ 200: WebhookSecretCreatedResponse;
12779
14995
  };
12780
14996
 
12781
14997
  export type CreateWebhookResponse = CreateWebhookResponses[keyof CreateWebhookResponses];
@@ -12950,6 +15166,42 @@ export type EnableWebhookResponses = {
12950
15166
  200: unknown;
12951
15167
  };
12952
15168
 
15169
+ export type RotateWebhookSecretData = {
15170
+ body?: never;
15171
+ path: {
15172
+ /**
15173
+ * Webhook ID
15174
+ */
15175
+ id: string;
15176
+ };
15177
+ query?: never;
15178
+ url: '/api/v1/webhooks/{id}/rotate-secret';
15179
+ };
15180
+
15181
+ export type RotateWebhookSecretErrors = {
15182
+ /**
15183
+ * Webhook not found
15184
+ */
15185
+ 404: unknown;
15186
+ /**
15187
+ * A previous rotation overlap window is still active
15188
+ */
15189
+ 409: unknown;
15190
+ /**
15191
+ * Encryption key not configured
15192
+ */
15193
+ 500: unknown;
15194
+ };
15195
+
15196
+ export type RotateWebhookSecretResponses = {
15197
+ /**
15198
+ * Secret rotated. Body includes the new raw secret exactly once.
15199
+ */
15200
+ 200: RotateWebhookSecretResponse;
15201
+ };
15202
+
15203
+ export type RotateWebhookSecretResponse2 = RotateWebhookSecretResponses[keyof RotateWebhookSecretResponses];
15204
+
12953
15205
  export type TestWebhookData = {
12954
15206
  body?: never;
12955
15207
  path: {