@artifact-keeper/sdk 1.7.3 → 1.10.0

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
@@ -80,7 +80,7 @@ export type AddProjectMemberRequest = {
80
80
  actions: Array<string>;
81
81
  principal_id: string;
82
82
  /**
83
- * "user" or "group".
83
+ * "user", "service_account" or "group".
84
84
  */
85
85
  principal_type: string;
86
86
  };
@@ -98,6 +98,13 @@ export type AdminUserResponse = {
98
98
  id: string;
99
99
  is_active: boolean;
100
100
  is_admin: boolean;
101
+ /**
102
+ * Whether this row is a service account rather than a person (#3634).
103
+ *
104
+ * `list_users` already read this column; it was dropped here, leaving
105
+ * clients no way to tell the two kinds of principal apart.
106
+ */
107
+ is_service_account: boolean;
101
108
  last_login_at?: string | null;
102
109
  must_change_password: boolean;
103
110
  username: string;
@@ -173,11 +180,50 @@ export type AnnouncePeerRequest = {
173
180
  };
174
181
 
175
182
  export type ApiTokenCreatedResponse = {
183
+ /**
184
+ * When the token expires (`None` = never). Authoritative from the mint,
185
+ * including any expiration the instance policy applied (#3460).
186
+ */
187
+ expires_at?: string | null;
176
188
  id: string;
177
189
  name: string;
190
+ /**
191
+ * True when the instance token expiration policy shaped this mint
192
+ * (applied a default or enforced the permitted range).
193
+ */
194
+ policy_applied: boolean;
178
195
  token: string;
179
196
  };
180
197
 
198
+ /**
199
+ * The API token expiration policy, as stored and as served by the admin API.
200
+ */
201
+ export type ApiTokenExpiryPolicy = {
202
+ /**
203
+ * Whether service-account token mints are subject to the policy.
204
+ * Defaults to false: expiring the credential a pipeline runs on is an
205
+ * outage on a schedule, so it must be an explicit opt-in.
206
+ */
207
+ apply_to_service_accounts?: boolean;
208
+ /**
209
+ * Applied when an enforced request omits `expires_in_days`. `None`
210
+ * means such requests are rejected instead.
211
+ */
212
+ default_days?: number | null;
213
+ /**
214
+ * Maximum acceptable `expires_in_days` while enforcing (inclusive).
215
+ */
216
+ max_days: number;
217
+ /**
218
+ * Minimum acceptable `expires_in_days` while enforcing (inclusive).
219
+ */
220
+ min_days: number;
221
+ /**
222
+ * When false the policy is entirely inert (historical behaviour).
223
+ */
224
+ require_expiration: boolean;
225
+ };
226
+
181
227
  export type ApiTokenListResponse = {
182
228
  items: Array<ApiTokenResponse>;
183
229
  };
@@ -402,6 +448,24 @@ export type ArtifactResponse = {
402
448
  */
403
449
  revision?: number | null;
404
450
  size_bytes: number;
451
+ /**
452
+ * Id of the user that uploaded this artifact (#3271), mirroring
453
+ * [`ArtifactVersionResponse::uploaded_by`] (#2397). Always serialized —
454
+ * `null` for anonymous/unknown uploads and for proxy-cached objects,
455
+ * which have no `artifacts` row — so the UI can rely on the key being
456
+ * present.
457
+ */
458
+ uploaded_by?: string | null;
459
+ /**
460
+ * Display name for [`Self::uploaded_by`], resolved server-side so the UI
461
+ * does not have to follow a bare UUID with an admin-only user lookup
462
+ * (#3271). `null` whenever `uploaded_by` is `null`, and also when the
463
+ * referenced user row no longer exists (a deleted account leaves the id
464
+ * on the artifact). Populated by the listing and per-artifact metadata
465
+ * endpoints; other responses that build an `ArtifactResponse` leave it
466
+ * unresolved.
467
+ */
468
+ uploaded_by_username?: string | null;
405
469
  version?: string | null;
406
470
  /**
407
471
  * Optional human tag recorded for this revision (from the
@@ -533,6 +597,26 @@ export type AuditLogListResponse = {
533
597
  * Authentication provider availability.
534
598
  */
535
599
  export type AuthConfig = {
600
+ /**
601
+ * Whether the verified-admin break-glass local login path is available
602
+ * (issue #2571). Unlike `local_login_enabled` — which only advertises
603
+ * the full local form on explicit `ALLOW_LOCAL_ADMIN_LOGIN=true` opt-in —
604
+ * this reflects the default #443 break-glass: with SSO enabled it is
605
+ * `true` unless the operator opted into strict SSO-only via
606
+ * `SSO_DISABLE_ADMIN_BREAK_GLASS`. Display-only: the login endpoint
607
+ * independently enforces the same policy
608
+ * (`api::handlers::auth::local_login_gate`), so this flag never grants
609
+ * access by itself.
610
+ *
611
+ * **Admin-only (#3489).** It answers "is there a local admin password
612
+ * path into this instance?", which is exactly the recon an anonymous
613
+ * attacker wants before probing `/api/v1/auth/login`, so it is omitted
614
+ * for anonymous and non-admin callers like the other security-posture
615
+ * fields. The login UI does not consume it — it decides whether to show
616
+ * the credentials form from `local_login_enabled`, and `?fallback=local`
617
+ * remains the admin recovery route.
618
+ */
619
+ admin_break_glass_enabled?: boolean | null;
536
620
  /**
537
621
  * Whether an LDAP directory is configured.
538
622
  */
@@ -553,6 +637,16 @@ export type AuthConfig = {
553
637
  * Whether an OIDC provider is configured.
554
638
  */
555
639
  oidc_enabled: boolean;
640
+ /**
641
+ * Whether the web UI should attempt silent SSO auto-login (an invisible
642
+ * OIDC `prompt=none` check-sso probe) when an OIDC provider is enabled.
643
+ * Kill switch: `OIDC_SILENT_SSO=false` (default `true`). Display-only:
644
+ * the flag only tells the frontend whether to *initiate* the silent
645
+ * attempt; the SSO endpoints enforce all authentication policy
646
+ * themselves, and anonymous visitors are never redirected to a visible
647
+ * IdP login page by the silent flow.
648
+ */
649
+ silent_sso_enabled: boolean;
556
650
  /**
557
651
  * Whether SAML SSO is configured (derived from the SSO admin settings in the DB,
558
652
  * but for this endpoint we report whether the OIDC issuer is set as a proxy).
@@ -560,6 +654,35 @@ export type AuthConfig = {
560
654
  sso_enabled: boolean;
561
655
  };
562
656
 
657
+ /**
658
+ * Non-secret provider settings for an `aws_ecr` / `aws_codeartifact` upstream
659
+ * (#1559).
660
+ */
661
+ export type AwsUpstreamAuthRequest = {
662
+ /**
663
+ * CodeArtifact only: domain name. Required for `aws_codeartifact`.
664
+ */
665
+ domain?: string | null;
666
+ /**
667
+ * CodeArtifact only: account id owning the domain. Defaults to the
668
+ * caller's account.
669
+ */
670
+ domain_owner?: string | null;
671
+ /**
672
+ * CodeArtifact only: requested token lifetime in seconds (0, or
673
+ * 900..=43200). Defaults to the AWS default of 12 hours.
674
+ */
675
+ duration_seconds?: number | null;
676
+ /**
677
+ * AWS region of the registry or domain, e.g. `us-east-1`.
678
+ */
679
+ region: string;
680
+ /**
681
+ * ECR only: registry (account) id, used to pin the upstream host.
682
+ */
683
+ registry_id?: string | null;
684
+ };
685
+
563
686
  export type BackupListResponse = {
564
687
  items: Array<BackupResponse>;
565
688
  total: number;
@@ -579,6 +702,41 @@ export type BackupResponse = {
579
702
  type: string;
580
703
  };
581
704
 
705
+ /**
706
+ * What this registry knows about a base image: filled in only when the
707
+ * reference names an image stored here (a local repository, or a remote
708
+ * repository's cache), otherwise `found: false` and the console falls back
709
+ * to guessing from the name.
710
+ */
711
+ export type BaseImageInfo = {
712
+ architecture?: string | null;
713
+ digest?: string | null;
714
+ found: boolean;
715
+ /**
716
+ * Whether the image carries conda.
717
+ */
718
+ has_conda: boolean;
719
+ /**
720
+ * Whether the image carries pip (a `pip install` in its history or a
721
+ * Python image label).
722
+ */
723
+ has_pip: boolean;
724
+ os?: string | null;
725
+ /**
726
+ * `<repo>/<image>:<tag>` inside this registry, when found.
727
+ */
728
+ reference?: string | null;
729
+ /**
730
+ * apt | dnf | microdnf | yum | apk, from the image's build history and
731
+ * labels; absent when the image does not say.
732
+ */
733
+ system_manager?: string | null;
734
+ /**
735
+ * The user the base image runs as; the spec's `user` defaults to it.
736
+ */
737
+ user?: string | null;
738
+ };
739
+
582
740
  /**
583
741
  * One downloader (or the anonymous bucket) of an affected artifact.
584
742
  */
@@ -617,6 +775,14 @@ export type BlastRadiusResponse = {
617
775
  downloaders: Array<BlastDownloader>;
618
776
  page: number;
619
777
  per_page: number;
778
+ /**
779
+ * Exposure through proxy-cached content (#3397).
780
+ */
781
+ proxy_exposure: ProxyBlastRadius;
782
+ /**
783
+ * **Hosted content only.** Every field here is artifact-keyed; see
784
+ * [`ProxyBlastRadius`] for proxy-cached exposure.
785
+ */
620
786
  summary: BlastRadiusSummary;
621
787
  target: BlastRadiusTargetInfo;
622
788
  /**
@@ -929,9 +1095,20 @@ export type CiOidcToggleRequest = {
929
1095
 
930
1096
  export type CiTokenRequest = {
931
1097
  /**
932
- * UUID of the `ci_oidc_providers` row to use for validation.
1098
+ * Optional UUID of the `ci_oidc_providers` row to validate against.
1099
+ *
1100
+ * Leave it out — and omit the body entirely — to have the provider
1101
+ * resolved from the assertion's own `iss` claim (#3548). The UUID is
1102
+ * server-generated and only published by the admin-only
1103
+ * `GET /api/v1/admin/ci-oidc`, so requiring it here meant a keyless CI
1104
+ * job had to authenticate with the admin password first.
1105
+ *
1106
+ * It is still honoured as an explicit override, for callers written
1107
+ * against the pre-#3548 shape and for instances that configure two
1108
+ * enabled providers on the same issuer. It must agree with the
1109
+ * assertion's `iss`; a provider that does not is a 400.
933
1110
  */
934
- provider_id: string;
1111
+ provider_id?: string | null;
935
1112
  };
936
1113
 
937
1114
  export type CiTokenResponse = {
@@ -1070,8 +1247,18 @@ export type CreateApiTokenRequest = {
1070
1247
  * Create API token response
1071
1248
  */
1072
1249
  export type CreateApiTokenResponse = {
1250
+ /**
1251
+ * When the token expires (`None` = never). Authoritative from the mint,
1252
+ * including any expiration the instance policy applied (#3460).
1253
+ */
1254
+ expires_at?: string | null;
1073
1255
  id: string;
1074
1256
  name: string;
1257
+ /**
1258
+ * True when the instance token expiration policy shaped this mint
1259
+ * (applied a default or enforced the permitted range).
1260
+ */
1261
+ policy_applied: boolean;
1075
1262
  token: string;
1076
1263
  };
1077
1264
 
@@ -1189,6 +1376,18 @@ export type CreateGroupRequest = {
1189
1376
  name: string;
1190
1377
  };
1191
1378
 
1379
+ export type CreateImageBuildRequest = {
1380
+ /**
1381
+ * Image path within the repository (`team/app`).
1382
+ */
1383
+ image: string;
1384
+ spec: ImageBuildSpec;
1385
+ /**
1386
+ * Tag to push (`2.56.0-genomics`).
1387
+ */
1388
+ tag: string;
1389
+ };
1390
+
1192
1391
  export type CreateInstanceRequest = {
1193
1392
  api_key: string;
1194
1393
  name: string;
@@ -1260,6 +1459,12 @@ export type CreateMigrationRequest = {
1260
1459
  };
1261
1460
 
1262
1461
  export type CreateOidcConfigRequest = {
1462
+ /**
1463
+ * IdP group whose members are granted the admin role on login.
1464
+ * Persisted as `attribute_mapping.admin_group`, the key the OIDC
1465
+ * callback reads for admin elevation (#3420).
1466
+ */
1467
+ admin_group?: string | null;
1263
1468
  /**
1264
1469
  * Opt-in compatibility flag (migration 144): when `true` the provider
1265
1470
  * accepts ID tokens signed with RSA keys shorter than 2048 bits via a
@@ -1346,8 +1551,18 @@ export type CreateRepoTokenRequest = {
1346
1551
  * contains the plaintext value and is only shown once.
1347
1552
  */
1348
1553
  export type CreateRepoTokenResponse = {
1554
+ /**
1555
+ * When the token expires (`None` = never). Authoritative from the mint,
1556
+ * including any expiration the instance policy applied (#3460).
1557
+ */
1558
+ expires_at?: string | null;
1349
1559
  id: string;
1350
1560
  name: string;
1561
+ /**
1562
+ * True when the instance token expiration policy shaped this mint
1563
+ * (applied a default or enforced the permitted range).
1564
+ */
1565
+ policy_applied: boolean;
1351
1566
  repository_key: string;
1352
1567
  /**
1353
1568
  * The full token value (only returned at creation time).
@@ -1460,7 +1675,7 @@ export type CreateRepositoryRequest = {
1460
1675
  * - Any other non-empty string — custom index prefix.
1461
1676
  *
1462
1677
  * Stored in `repository_config` under `pypi_upstream_index_path`.
1463
- * Only meaningful for PyPI / Poetry / Conda Remote repositories.
1678
+ * Only meaningful for PyPI / Poetry / Jupyter / Conda Remote repositories.
1464
1679
  */
1465
1680
  pypi_upstream_index_path?: string | null;
1466
1681
  quota_bytes?: number | null;
@@ -1535,6 +1750,13 @@ export type CreateSamlConfigRequest = {
1535
1750
  require_signed_assertions?: boolean | null;
1536
1751
  sign_requests?: boolean | null;
1537
1752
  slo_url?: string | null;
1753
+ /**
1754
+ * Optional URL-safe alias for the public SAML routes (#2583). Must
1755
+ * match `^[a-z0-9][a-z0-9_-]*$`, be at most 64 characters, not look
1756
+ * like a UUID, and be unique across SAML configurations. Omit it to
1757
+ * keep the configuration addressable by its `id` only.
1758
+ */
1759
+ slug?: string | null;
1538
1760
  sp_entity_id?: string | null;
1539
1761
  sso_url: string;
1540
1762
  /**
@@ -1675,8 +1897,18 @@ export type CreateTokenRequest = {
1675
1897
  };
1676
1898
 
1677
1899
  export type CreateTokenResponse = {
1900
+ /**
1901
+ * When the token expires (`None` = never). Service-account tokens are
1902
+ * exempt from the instance expiration policy unless the admin opted them
1903
+ * in (`apply_to_service_accounts`) (#3460).
1904
+ */
1905
+ expires_at?: string | null;
1678
1906
  id: string;
1679
1907
  name: string;
1908
+ /**
1909
+ * True when the instance token expiration policy shaped this mint.
1910
+ */
1911
+ policy_applied: boolean;
1680
1912
  token: string;
1681
1913
  };
1682
1914
 
@@ -1775,6 +2007,19 @@ export type CurationCreateRuleRequest = {
1775
2007
 
1776
2008
  export type CurationPackageResponse = {
1777
2009
  architecture?: string | null;
2010
+ attestation_error?: string | null;
2011
+ attestation_identity?: string | null;
2012
+ attestation_issuer?: string | null;
2013
+ attestation_owner?: string | null;
2014
+ /**
2015
+ * Attestation verification record (#2955, surfaced by #3230):
2016
+ * `unverified` | `verified` | `failed`, with the certificate-bound identity
2017
+ * on success and the specific failing check otherwise. Without these an
2018
+ * operator cannot answer "which packages verified, and against which
2019
+ * certificate identity" without querying the database directly.
2020
+ */
2021
+ attestation_state: string;
2022
+ attestation_verified_at?: string | null;
1778
2023
  checksum_sha256?: string | null;
1779
2024
  evaluated_at?: string | null;
1780
2025
  evaluated_by?: string | null;
@@ -2415,6 +2660,60 @@ export type DtVulnerability = {
2415
2660
  vulnId: string;
2416
2661
  };
2417
2662
 
2663
+ /**
2664
+ * Per-repository egress proxy settings (#2469, #2811).
2665
+ *
2666
+ * `proxy_url` is **write-only**: it is encrypted at rest and never returned.
2667
+ * [`EgressProxyResponse`] echoes a redacted form (`http:/***@proxy:3128`)
2668
+ * so an operator can confirm the host and port without recovering the
2669
+ * credentials, exactly as `upstream_auth_configured` does for upstream
2670
+ * credentials.
2671
+ */
2672
+ export type EgressProxyRequest = {
2673
+ /**
2674
+ * `inherit` (follow the process `HTTP_PROXY`/`HTTPS_PROXY`/`NO_PROXY`
2675
+ * environment — the default), `direct` (never proxy this repository, even
2676
+ * when the environment sets one), or `explicit` (use `proxy_url`, ignoring
2677
+ * the environment entirely).
2678
+ */
2679
+ mode: string;
2680
+ /**
2681
+ * Comma-separated hosts / domain suffixes / CIDRs that bypass the proxy
2682
+ * for this repository. Only meaningful when `mode` is `explicit`.
2683
+ */
2684
+ no_proxy?: string | null;
2685
+ /**
2686
+ * Proxy endpoint, `scheme://host[:port]`, http or https. May embed
2687
+ * `user:pass@` credentials. Required when `mode` is `explicit`.
2688
+ * Write-only, never returned in responses.
2689
+ */
2690
+ proxy_url?: string | null;
2691
+ };
2692
+
2693
+ /**
2694
+ * Read-back of a repository's egress-proxy settings. Carries no secret.
2695
+ */
2696
+ export type EgressProxyResponse = {
2697
+ /**
2698
+ * `inherit`, `direct` or `explicit`.
2699
+ */
2700
+ mode: string;
2701
+ /**
2702
+ * The configured bypass list, if any.
2703
+ */
2704
+ no_proxy?: string | null;
2705
+ /**
2706
+ * Whether the configured proxy URL carries credentials. The credentials
2707
+ * themselves are never returned.
2708
+ */
2709
+ proxy_credentials_configured: boolean;
2710
+ /**
2711
+ * The configured proxy with any credentials replaced by `***`. `None`
2712
+ * unless `mode` is `explicit`.
2713
+ */
2714
+ proxy_url?: string | null;
2715
+ };
2716
+
2418
2717
  export type EmailSubscriptionListResponse = {
2419
2718
  subscriptions: Array<EmailSubscriptionResponse>;
2420
2719
  };
@@ -2465,6 +2764,37 @@ export type ExchangeCodeResponse = {
2465
2764
  token_type: string;
2466
2765
  };
2467
2766
 
2767
+ /**
2768
+ * One finding as an external scanner reports it.
2769
+ *
2770
+ * Deliberately the wire shape of [`FindingResponse`] minus the fields the
2771
+ * server owns (ids, acknowledgment state, timestamps), so a scanner that can
2772
+ * read AK's findings can post findings back in the same vocabulary.
2773
+ */
2774
+ export type ExternalFindingInput = {
2775
+ affected_component?: string | null;
2776
+ affected_version?: string | null;
2777
+ cve_id?: string | null;
2778
+ description?: string | null;
2779
+ fixed_version?: string | null;
2780
+ /**
2781
+ * Scanner severity token. Normalized through the shared classifier, so a
2782
+ * vendor's own spelling (`Moderate`, `NEGLIGIBLE`, ...) is accepted.
2783
+ *
2784
+ * An UNRECOGNIZED token classifies as `high`, not `info` — fail-closed,
2785
+ * per #3306. An unknown verdict from an unknown scanner is the one case
2786
+ * where guessing low would silently disarm every gate that reads severity.
2787
+ */
2788
+ severity: string;
2789
+ /**
2790
+ * Vendor identity for this finding. Defaults to the submission's
2791
+ * `scanner` when omitted, and is what `?source=` filters on (#3410).
2792
+ */
2793
+ source?: string | null;
2794
+ source_url?: string | null;
2795
+ title: string;
2796
+ };
2797
+
2468
2798
  export type FacetValue = {
2469
2799
  count: number;
2470
2800
  value: string;
@@ -2716,79 +3046,328 @@ export type IdentityResponse = {
2716
3046
  peer_id: string;
2717
3047
  };
2718
3048
 
2719
- export type InitTransferBody = {
2720
- artifact_id: string;
2721
- chunk_size?: number | null;
3049
+ export type ImageBuildListResponse = {
3050
+ items: Array<ImageBuildResponse>;
3051
+ total: number;
2722
3052
  };
2723
3053
 
2724
- /**
2725
- * Request to install a plugin from Git
2726
- */
2727
- export type InstallFromGitRequest = {
3054
+ export type ImageBuildResponse = {
3055
+ containerfile: string;
3056
+ created_at: string;
3057
+ digest?: string | null;
3058
+ error?: string | null;
3059
+ finished_at?: string | null;
3060
+ id: string;
3061
+ image: string;
3062
+ log_bytes: number;
2728
3063
  /**
2729
- * Git ref (tag, branch, or commit)
3064
+ * `<repo key>/<image>:<tag>` the reference within this registry.
2730
3065
  */
2731
- ref?: string | null;
3066
+ reference: string;
3067
+ repository_key: string;
3068
+ requested_by: string;
3069
+ spec: unknown;
3070
+ started_at?: string | null;
2732
3071
  /**
2733
- * Git repository URL
3072
+ * queued | running | succeeded | failed
2734
3073
  */
2735
- url: string;
3074
+ status: string;
3075
+ tag: string;
2736
3076
  };
2737
3077
 
2738
- /**
2739
- * Request for installing from local file path
2740
- */
2741
- export type InstallFromLocalRequest = {
3078
+ export type ImageBuildSettingsResponse = {
2742
3079
  /**
2743
- * Local filesystem path to plugin directory
3080
+ * Building is restricted to administrators on this instance.
2744
3081
  */
2745
- path: string;
3082
+ admin_only: boolean;
3083
+ /**
3084
+ * Whole-Dockerfile specs are accepted on this instance.
3085
+ */
3086
+ allow_dockerfile: boolean;
3087
+ allow_run: boolean;
3088
+ base_allowlist: Array<string>;
3089
+ /**
3090
+ * Whether the caller may build here: repository write access, plus
3091
+ * admin when `admin_only`.
3092
+ */
3093
+ caller_may_build: boolean;
3094
+ /**
3095
+ * False when `AK_BUILDKIT_ADDR` / `AK_IMAGE_BUILD_PUSH_REGISTRY` are unset.
3096
+ */
3097
+ enabled: boolean;
3098
+ max_concurrent: number;
3099
+ /**
3100
+ * The pip index every generated `pip install` uses, when configured.
3101
+ */
3102
+ pip_index_url?: string | null;
3103
+ /**
3104
+ * The address buildkitd pushes to, for display.
3105
+ */
3106
+ push_registry?: string | null;
3107
+ /**
3108
+ * Whether this repository can receive builds (local container repo).
3109
+ */
3110
+ repository_buildable: boolean;
3111
+ /**
3112
+ * Package managers a spec may install with, for the UI's dropdown.
3113
+ */
3114
+ supported_package_managers: Array<string>;
3115
+ timeout_secs: number;
2746
3116
  };
2747
3117
 
2748
- export type InvalidateCacheQuery = {
3118
+ /**
3119
+ * What a user asks for. Either a structured spec (`base_image` plus
3120
+ * package groups, env, labels, user, workdir) or, when the instance allows
3121
+ * it, a whole `dockerfile` the server only checks and stamps.
3122
+ */
3123
+ export type ImageBuildSpec = {
3124
+ apt?: Array<string>;
2749
3125
  /**
2750
- * Artifact path to evict from the proxy cache. Same shape as the path
2751
- * segment of `GET /api/v1/repositories/{key}/artifacts/{path}`.
2752
- * Path-traversal segments such as `..` are rejected by
2753
- * `ProxyService::cache_storage_key` (covered by
2754
- * `test_invalidate_cache_by_key_rejects_invalid_path`).
3126
+ * The image to build on (`python:3.12-slim`); must match the
3127
+ * administrator's base allowlist when one is configured. Ignored when
3128
+ * `dockerfile` is set (its FROM lines are checked instead).
2755
3129
  */
2756
- path: string;
3130
+ base_image?: string;
3131
+ conda?: Array<string>;
3132
+ conda_channels?: Array<string>;
3133
+ /**
3134
+ * A complete Dockerfile replacing the structured fields; accepted only
3135
+ * when `AK_IMAGE_BUILD_ALLOW_DOCKERFILE=true`. Every FROM must match the
3136
+ * base allowlist; the spec label is appended so inspection still knows
3137
+ * what the image came from.
3138
+ */
3139
+ dockerfile?: string | null;
3140
+ /**
3141
+ * Environment variables baked into the image.
3142
+ */
3143
+ env?: {
3144
+ [key: string]: string;
3145
+ };
3146
+ /**
3147
+ * OCI labels baked into the image.
3148
+ */
3149
+ labels?: {
3150
+ [key: string]: string;
3151
+ };
3152
+ /**
3153
+ * Build pip groups in a separate stage and copy only the installed
3154
+ * packages into the final image, so build tooling and caches never ship.
3155
+ */
3156
+ multistage?: boolean;
3157
+ /**
3158
+ * Install steps, rendered in order.
3159
+ */
3160
+ packages?: Array<PackageGroup>;
3161
+ pip?: Array<string>;
3162
+ /**
3163
+ * Raw `RUN` lines. Refused unless `AK_IMAGE_BUILD_ALLOW_RUN=true`.
3164
+ */
3165
+ run?: Array<string>;
3166
+ /**
3167
+ * The user the image runs as (`app`, `1000`, `1000:100`). Required
3168
+ * when any system package group is present (they install as root).
3169
+ */
3170
+ user?: string | null;
3171
+ /**
3172
+ * Working directory the image starts in.
3173
+ */
3174
+ workdir?: string | null;
2757
3175
  };
2758
3176
 
2759
- export type InvalidateCacheResponse = {
2760
- invalidated: boolean;
2761
- path: string;
2762
- repository_key: string;
3177
+ export type ImageConfig = {
3178
+ cmd: Array<string>;
3179
+ entrypoint: Array<string>;
3180
+ env: {
3181
+ [key: string]: string;
3182
+ };
3183
+ exposed_ports: Array<string>;
3184
+ labels: {
3185
+ [key: string]: string;
3186
+ };
3187
+ user: string;
3188
+ working_dir: string;
2763
3189
  };
2764
3190
 
2765
- export type IssueResponse = {
2766
- artifact_id: string;
2767
- category: string;
2768
- check_result_id: string;
2769
- created_at: string;
2770
- description?: string | null;
2771
- id: string;
2772
- is_suppressed: boolean;
2773
- location?: string | null;
2774
- severity: string;
2775
- suppressed_at?: string | null;
2776
- suppressed_by?: string | null;
2777
- suppressed_reason?: string | null;
2778
- title: string;
3191
+ /**
3192
+ * One `history` row of the image config: the instruction that produced a
3193
+ * layer, joined to that layer when it produced one. This is the closest an
3194
+ * image gets to its Dockerfile when no provenance attestation carries the
3195
+ * real one.
3196
+ */
3197
+ export type ImageHistoryEntry = {
3198
+ comment?: string | null;
3199
+ created?: string | null;
3200
+ created_by: string;
3201
+ empty_layer: boolean;
3202
+ layer_digest?: string | null;
3203
+ size_bytes?: number | null;
2779
3204
  };
2780
3205
 
2781
- export type KeyListResponse = {
2782
- keys: Array<SigningKeyPublic>;
2783
- total: number;
3206
+ export type ImageInspect = {
3207
+ config: ImageConfig;
3208
+ /**
3209
+ * Digest of the manifest the details describe (the platform manifest
3210
+ * when `reference` resolved to an index).
3211
+ */
3212
+ digest: string;
3213
+ history: Array<ImageHistoryEntry>;
3214
+ /**
3215
+ * Digest of the index the reference points at, when it is one.
3216
+ */
3217
+ index_digest?: string | null;
3218
+ layers: Array<ImageLayer>;
3219
+ platforms: Array<ImagePlatform>;
3220
+ provenance?: null | ImageProvenance;
3221
+ /**
3222
+ * The reference that was inspected (`repo/image:tag`).
3223
+ */
3224
+ reference: string;
3225
+ size_bytes: number;
3226
+ /**
3227
+ * Which producer filled the document: `registry` (read from storage).
3228
+ */
3229
+ source: string;
2784
3230
  };
2785
3231
 
2786
- export type LabelEntrySchema = {
2787
- key: string;
2788
- value?: string;
3232
+ export type ImageLayer = {
3233
+ digest: string;
3234
+ media_type: string;
3235
+ size_bytes: number;
2789
3236
  };
2790
3237
 
2791
- export type LabelResponse = {
3238
+ export type ImagePlatform = {
3239
+ architecture: string;
3240
+ os: string;
3241
+ variant?: string | null;
3242
+ };
3243
+
3244
+ /**
3245
+ * What a BuildKit SLSA provenance attestation says about how the image
3246
+ * was built. `dockerfile` is present only for `mode=max` attestations,
3247
+ * which embed the source; the image builder always emits those.
3248
+ */
3249
+ export type ImageProvenance = {
3250
+ attestation_digest: string;
3251
+ build_type?: string | null;
3252
+ builder_id?: string | null;
3253
+ dockerfile?: string | null;
3254
+ dockerfile_name?: string | null;
3255
+ predicate_type?: string | null;
3256
+ };
3257
+
3258
+ /**
3259
+ * One external scanner's verdict on one artifact.
3260
+ */
3261
+ export type IngestExternalFindingsRequest = {
3262
+ /**
3263
+ * The artifact these findings are about.
3264
+ */
3265
+ artifact_id: string;
3266
+ /**
3267
+ * The findings. May be empty — a clean verdict is a verdict, and it is
3268
+ * what clears a previously-flagged artifact.
3269
+ */
3270
+ findings: Array<ExternalFindingInput>;
3271
+ /**
3272
+ * Vendor name, recorded as each finding's `source` unless the finding
3273
+ * overrides it. Required: an unattributed verdict cannot be filtered,
3274
+ * audited, or withdrawn.
3275
+ */
3276
+ scanner: string;
3277
+ /**
3278
+ * Vendor build/database version, recorded as `scan_results.scanner_version`.
3279
+ */
3280
+ scanner_version?: string | null;
3281
+ };
3282
+
3283
+ export type IngestExternalFindingsResponse = {
3284
+ artifact_id: string;
3285
+ findings_ingested: number;
3286
+ grade: string;
3287
+ repository_id: string;
3288
+ /**
3289
+ * The `scan_results` row written, already `completed`.
3290
+ */
3291
+ scan_id: string;
3292
+ /**
3293
+ * Repository security score after `recalculate_score`.
3294
+ */
3295
+ score: number;
3296
+ };
3297
+
3298
+ export type InitTransferBody = {
3299
+ artifact_id: string;
3300
+ chunk_size?: number | null;
3301
+ };
3302
+
3303
+ /**
3304
+ * Request to install a plugin from Git
3305
+ */
3306
+ export type InstallFromGitRequest = {
3307
+ /**
3308
+ * Git ref (tag, branch, or commit)
3309
+ */
3310
+ ref?: string | null;
3311
+ /**
3312
+ * Git repository URL
3313
+ */
3314
+ url: string;
3315
+ };
3316
+
3317
+ /**
3318
+ * Request for installing from local file path
3319
+ */
3320
+ export type InstallFromLocalRequest = {
3321
+ /**
3322
+ * Local filesystem path to plugin directory
3323
+ */
3324
+ path: string;
3325
+ };
3326
+
3327
+ export type InvalidateCacheQuery = {
3328
+ /**
3329
+ * Artifact path to evict from the proxy cache. Same shape as the path
3330
+ * segment of `GET /api/v1/repositories/{key}/artifacts/{path}`.
3331
+ * Path-traversal segments such as `..` are rejected by
3332
+ * `ProxyService::cache_storage_key` (covered by
3333
+ * `test_invalidate_cache_by_key_rejects_invalid_path`).
3334
+ */
3335
+ path: string;
3336
+ };
3337
+
3338
+ export type InvalidateCacheResponse = {
3339
+ invalidated: boolean;
3340
+ path: string;
3341
+ repository_key: string;
3342
+ };
3343
+
3344
+ export type IssueResponse = {
3345
+ artifact_id: string;
3346
+ category: string;
3347
+ check_result_id: string;
3348
+ created_at: string;
3349
+ description?: string | null;
3350
+ id: string;
3351
+ is_suppressed: boolean;
3352
+ location?: string | null;
3353
+ severity: string;
3354
+ suppressed_at?: string | null;
3355
+ suppressed_by?: string | null;
3356
+ suppressed_reason?: string | null;
3357
+ title: string;
3358
+ };
3359
+
3360
+ export type KeyListResponse = {
3361
+ keys: Array<SigningKeyPublic>;
3362
+ total: number;
3363
+ };
3364
+
3365
+ export type LabelEntrySchema = {
3366
+ key: string;
3367
+ value?: string;
3368
+ };
3369
+
3370
+ export type LabelResponse = {
2792
3371
  created_at: string;
2793
3372
  id: string;
2794
3373
  key: string;
@@ -2847,6 +3426,78 @@ export type LdapTestResult = {
2847
3426
  success: boolean;
2848
3427
  };
2849
3428
 
3429
+ /**
3430
+ * One repository's before/after in a ledger backfill (#3650).
3431
+ */
3432
+ export type LedgerBackfillRepository = {
3433
+ /**
3434
+ * `artifacts` bytes, excluding soft-deleted rows and legacy
3435
+ * `proxy-cache/%` keys — migration 182's `hosted_bytes` rule verbatim.
3436
+ */
3437
+ after_hosted_bytes: number;
3438
+ /**
3439
+ * `oci_blobs` bytes (every row counts; a `pending_delete_at` marker is
3440
+ * not a deletion and does not change the figure).
3441
+ */
3442
+ after_oci_bytes: number;
3443
+ /**
3444
+ * `proxy_cache_artifacts` bytes (every row counts). A breakdown of
3445
+ * `after_total_bytes`, not a disjoint bucket.
3446
+ */
3447
+ after_proxy_bytes: number;
3448
+ /**
3449
+ * Ledger total after the backfill: `hosted + proxy + oci`, the same sum
3450
+ * `/admin/stats.total_storage_bytes` aggregates.
3451
+ */
3452
+ after_total_bytes: number;
3453
+ /**
3454
+ * Ledger total before the backfill, or `null` when the repository had no
3455
+ * ledger row at all. A database restored from backup is the `null` case:
3456
+ * the restore inserts `artifacts` / `oci_blobs` / `proxy_cache_artifacts`
3457
+ * rows without firing migration 182's triggers, so no ledger row is ever
3458
+ * written for them.
3459
+ */
3460
+ before_total_bytes?: number | null;
3461
+ /**
3462
+ * `after_total_bytes - before_total_bytes`, counting a missing row as 0.
3463
+ */
3464
+ drift_bytes: number;
3465
+ repository_id: string;
3466
+ repository_key: string;
3467
+ };
3468
+
3469
+ /**
3470
+ * Result of `POST /api/v1/admin/storage/ledger/backfill` (#3650).
3471
+ */
3472
+ export type LedgerBackfillResponse = {
3473
+ /**
3474
+ * `/admin/stats.total_storage_bytes` as it reads after the backfill.
3475
+ */
3476
+ after_total_storage_bytes: number;
3477
+ /**
3478
+ * `/admin/stats.total_storage_bytes` as it read before the backfill.
3479
+ */
3480
+ before_total_storage_bytes: number;
3481
+ /**
3482
+ * Per-repository detail, ordered by repository key.
3483
+ */
3484
+ repositories: Array<LedgerBackfillRepository>;
3485
+ repositories_checked: number;
3486
+ /**
3487
+ * Repositories whose ledger total changed.
3488
+ */
3489
+ repositories_repaired: number;
3490
+ /**
3491
+ * Repositories deleted between the scan and their recompute. Not an
3492
+ * error — the ledger row went with them.
3493
+ */
3494
+ repositories_skipped: number;
3495
+ /**
3496
+ * Sum of the absolute per-repository corrections, in bytes.
3497
+ */
3498
+ total_drift_bytes: number;
3499
+ };
3500
+
2850
3501
  /**
2851
3502
  * Result of license compliance check.
2852
3503
  */
@@ -3007,6 +3658,18 @@ export type ListSbomsQuery = {
3007
3658
  export type ListUsersQuery = {
3008
3659
  is_active?: boolean | null;
3009
3660
  is_admin?: boolean | null;
3661
+ /**
3662
+ * Filter on the service-account discriminator (#3634).
3663
+ *
3664
+ * Service accounts are rows in `users`, so an unfiltered listing mixes
3665
+ * them in with people. A client building a principal picker for
3666
+ * `POST /api/v1/permissions` must be able to exclude them: that endpoint's
3667
+ * `validate_principal` requires `principal_type = "service_account"` for
3668
+ * such a row and rejects it as `"user"`, so offering one under `user` is a
3669
+ * guaranteed 400. `None` keeps the historical unfiltered behavior, which
3670
+ * the audit actor filter and the group member picker both want.
3671
+ */
3672
+ is_service_account?: boolean | null;
3010
3673
  page?: number | null;
3011
3674
  per_page?: number | null;
3012
3675
  search?: string | null;
@@ -3030,6 +3693,18 @@ export type LoginResponse = {
3030
3693
  must_change_password: boolean;
3031
3694
  refresh_token: string;
3032
3695
  token_type: string;
3696
+ /**
3697
+ * Set when the 2FA enforcement policy (#2805) requires this user to enrol
3698
+ * in TOTP before a session can be issued. `totp_token` then carries an
3699
+ * *enrollment ticket* rather than a verification ticket: redeem it at
3700
+ * `POST /auth/totp/enroll/setup` followed by
3701
+ * `POST /auth/totp/enroll/complete`, which returns the real session.
3702
+ *
3703
+ * A client that does not understand this field sees no `access_token` and
3704
+ * must not treat the response as a successful login. It is never set at the
3705
+ * same time as `totp_required`.
3706
+ */
3707
+ totp_enrollment_required?: boolean | null;
3033
3708
  totp_required?: boolean | null;
3034
3709
  totp_token?: string | null;
3035
3710
  };
@@ -3365,6 +4040,19 @@ export type OidcConfigResponse = {
3365
4040
  updated_at: string;
3366
4041
  };
3367
4042
 
4043
+ /**
4044
+ * One install step: which manager, which packages, and for conda which
4045
+ * channels. Groups render in the order given.
4046
+ */
4047
+ export type PackageGroup = {
4048
+ /**
4049
+ * conda channels (`conda-forge`, `bioconda`); conda groups only.
4050
+ */
4051
+ channels?: Array<string>;
4052
+ manager: PackageManager;
4053
+ packages?: Array<string>;
4054
+ };
4055
+
3368
4056
  export type PackageListQuery = {
3369
4057
  limit?: number;
3370
4058
  offset?: number;
@@ -3377,6 +4065,14 @@ export type PackageListResponse = {
3377
4065
  pagination: Pagination;
3378
4066
  };
3379
4067
 
4068
+ /**
4069
+ * A package manager a spec may install with. The system managers run as
4070
+ * root in the final stage and need the spec to name the `user` the image
4071
+ * runs as afterwards; `pip` moves to a builder stage when `multistage` is
4072
+ * set; `conda` always installs in the final stage.
4073
+ */
4074
+ export type PackageManager = 'apt' | 'dnf' | 'microdnf' | 'yum' | 'apk' | 'pip' | 'conda';
4075
+
3380
4076
  export type PackageResponse = {
3381
4077
  created_at: string;
3382
4078
  description?: string | null;
@@ -3446,6 +4142,37 @@ export type PackageVersionsResponse = {
3446
4142
  versions: Array<PackageVersionResponse>;
3447
4143
  };
3448
4144
 
4145
+ /**
4146
+ * Query parameters for `POST /api/v1/admin/packages/backfill`.
4147
+ */
4148
+ export type PackagesBackfillQuery = {
4149
+ /**
4150
+ * Restrict the walk to one repository. Omit to walk every hosted
4151
+ * repository in a catalog-eligible format.
4152
+ */
4153
+ repository_key?: string | null;
4154
+ };
4155
+
4156
+ export type PackagesBackfillResponse = {
4157
+ /**
4158
+ * Rows whose upsert errored; the walk continues past them.
4159
+ */
4160
+ artifacts_failed: number;
4161
+ /**
4162
+ * Live artifact rows considered.
4163
+ */
4164
+ artifacts_scanned: number;
4165
+ /**
4166
+ * Rows with no derivable package coordinates (index/sidecar rows).
4167
+ */
4168
+ artifacts_skipped: number;
4169
+ message: string;
4170
+ /**
4171
+ * Catalog upserts performed.
4172
+ */
4173
+ packages_registered: number;
4174
+ };
4175
+
3449
4176
  /**
3450
4177
  * Pagination metadata for list responses.
3451
4178
  *
@@ -3681,7 +4408,19 @@ export type PluginType = 'format_handler' | 'storage_backend' | 'authentication'
3681
4408
  export type PolicyExecutionResult = {
3682
4409
  artifacts_matched: number;
3683
4410
  artifacts_removed: number;
4411
+ /**
4412
+ * Bytes actually reclaimed by this run. Always zero for a dry run.
4413
+ */
3684
4414
  bytes_freed: number;
4415
+ /**
4416
+ * Bytes held by the `artifacts_matched` rows -- what a run *would*
4417
+ * reclaim. Populated for a dry run as well as a live one, which is the
4418
+ * whole point of a preview: `bytes_freed` is deliberately zero on a dry
4419
+ * run (nothing was freed), so before this field a preview could report
4420
+ * which artifacts it would delete but never how much space that was
4421
+ * worth (#2024).
4422
+ */
4423
+ bytes_matched: number;
3685
4424
  dry_run: boolean;
3686
4425
  errors: Array<string>;
3687
4426
  policy_id: string;
@@ -3867,78 +4606,313 @@ export type PromotionRuleResponse = {
3867
4606
  };
3868
4607
 
3869
4608
  /**
3870
- * Body for declaring that a locally-owned PyPI project tracks an upstream one.
4609
+ * Exposure through proxy-cached content, reported alongside the hosted
4610
+ * numbers (#3397).
4611
+ *
4612
+ * `summary` above is computed over `scan_findings` joined to `artifacts` and
4613
+ * `download_statistics` — all three artifact-keyed. Proxy-cached bytes have no
4614
+ * `artifacts` row by design, and their downloads land in
4615
+ * `proxy_download_statistics` keyed by `proxy_cache_id`, so the hosted numbers
4616
+ * were not merely incomplete for proxy content: they were structurally
4617
+ * incapable of being non-zero for it. A confident zero to a security question
4618
+ * is worse than an error, so this block exists even when it is all zeros — an
4619
+ * operator can then see that proxy content WAS searched.
4620
+ *
4621
+ * Attribution runs through `proxy_scan_findings` (#3395). Before that table
4622
+ * existed there was no per-CVE detail for proxy content to attribute a
4623
+ * download to, which is why #3397 depended on #3395.
3871
4624
  */
3872
- export type PypiTrackRequest = {
4625
+ export type ProxyBlastRadius = {
3873
4626
  /**
3874
- * Upstream Simple index project URL this local project tracks, e.g.
3875
- * `https://pypi.org/simple/acme-sdk/`. Recorded and emitted as the PEP 708
3876
- * `tracks` value.
4627
+ * Distinct proxy-cached digests carrying this CVE.
3877
4628
  */
3878
- tracks_url: string;
3879
- };
3880
-
3881
- /**
3882
- * A single PEP 708 `tracks` declaration.
3883
- */
3884
- export type PypiTrackResponse = {
4629
+ affected_digest_count: number;
3885
4630
  /**
3886
- * PEP 503 normalized project name.
4631
+ * Repositories whose proxy cache holds one of those digests.
3887
4632
  */
3888
- normalized_name: string;
3889
- repository_key: string;
3890
- tracks_url: string;
3891
- };
3892
-
3893
- /**
3894
- * All `tracks` declarations on a repository.
3895
- */
3896
- export type PypiTracksListResponse = {
3897
- items: Array<PypiTrackResponse>;
4633
+ affected_repo_count: number;
4634
+ /**
4635
+ * Whether any such pull was anonymous.
4636
+ */
4637
+ anonymous_download_present: boolean;
4638
+ /**
4639
+ * `included` | `not_applicable` see the constants. Never omit this:
4640
+ * it is what tells a reader whether a zero below means "searched, nothing
4641
+ * found" or "not searched".
4642
+ */
4643
+ coverage: string;
4644
+ /**
4645
+ * Proxy download events of affected digests in the window.
4646
+ */
4647
+ download_count: number;
4648
+ /**
4649
+ * Distinct authenticated users who pulled one.
4650
+ */
4651
+ downloader_user_count: number;
3898
4652
  };
3899
4653
 
3900
4654
  /**
3901
- * Paginated admin quality-check list response (#2419).
4655
+ * A CVE-identified finding retained from an inline proxy scan so it can be
4656
+ * persisted into `proxy_scan_findings` and answered back to an operator
4657
+ * asking "which CVE blocked my build?" (#3395).
4658
+ *
4659
+ * Deliberately narrower than [`RawFinding`]: only the columns the digest-keyed
4660
+ * table stores. `description`, `source` and `source_url` are dropped because
4661
+ * they are scanner prose that would bloat a row written on every proxied
4662
+ * download, and because none of them identify the vulnerability.
4663
+ *
4664
+ * `cve_id` is non-optional here while it is optional on [`RawFinding`]: a
4665
+ * finding a scanner could not attach a CVE id to has nothing to look up, and
4666
+ * the table's identity key is the CVE. Such findings are dropped on the way
4667
+ * in — they still count toward `findings_count` on the verdict, which is
4668
+ * computed from the raw list before this projection runs.
3902
4669
  */
3903
- export type QualityCheckListResponse = {
3904
- items: Array<CheckResponse>;
3905
- page: number;
3906
- per_page: number;
3907
- total: number;
3908
- };
3909
-
3910
- export type QuarantineActionResponse = {
3911
- artifact_id: string;
3912
- message: string;
3913
- new_status: string;
3914
- };
3915
-
3916
- export type QuarantineNowRequest = {
4670
+ export type ProxyFinding = {
3917
4671
  /**
3918
- * Reason shown to developers whose downloads are blocked.
4672
+ * Canonical vulnerability id, e.g. `CVE-2021-44228` or `GHSA-...`.
3919
4673
  */
3920
- reason?: string | null;
3921
- };
3922
-
3923
- export type QuarantineStatusResponse = {
3924
- artifact_id: string;
3925
- is_blocked: boolean;
4674
+ cve_id: string;
3926
4675
  /**
3927
- * Why the artifact is held, when one was recorded by a scan policy or an
3928
- * admin. This is the only surface that discloses the reason: blocked
3929
- * downloads return a generic message because they are reachable
3930
- * anonymously on public repositories (#2912).
4676
+ * Version that resolves it, when the scanner reported one the single
4677
+ * most actionable field for an operator whose build was just blocked.
3931
4678
  */
3932
- quarantine_reason?: string | null;
3933
- quarantine_status?: string | null;
3934
- quarantine_until?: string | null;
4679
+ fixed_version?: string | null;
4680
+ /**
4681
+ * Component the vulnerability was matched against.
4682
+ */
4683
+ package_name?: string | null;
4684
+ package_version?: string | null;
4685
+ /**
4686
+ * Lowercase severity token (`critical`/`high`/`medium`/`low`/`info`),
4687
+ * matching the tokens stored on `proxy_scan_results.max_severity`.
4688
+ */
4689
+ severity: string;
4690
+ title?: string | null;
3935
4691
  };
3936
4692
 
3937
- export type QuickSearchResponse = {
3938
- results: Array<SearchResultItem>;
4693
+ export type ProxyRescanRequest = {
4694
+ /**
4695
+ * Cache path within this repository, e.g.
4696
+ * `simple/click/click-8.0.0-py3-none-any.whl`. Path-keyed for the same
4697
+ * cross-tenant reason the read endpoint is.
4698
+ */
4699
+ path: string;
3939
4700
  };
3940
4701
 
3941
- export type ReEvaluateRequest = {
4702
+ export type ProxyRescanResponse = {
4703
+ critical_count: number;
4704
+ digest: string;
4705
+ /**
4706
+ * Per-CVE detail from this run, bounded to [`MAX_PROXY_FINDINGS`].
4707
+ */
4708
+ findings: Array<ProxyFinding>;
4709
+ findings_count: number;
4710
+ high_count: number;
4711
+ low_count: number;
4712
+ max_severity?: string | null;
4713
+ medium_count: number;
4714
+ /**
4715
+ * Components cataloged and persisted, i.e. how much SBOM this rescan
4716
+ * produced. Zero means the scanner reported no inventory for these bytes.
4717
+ */
4718
+ package_count: number;
4719
+ path: string;
4720
+ repository_key: string;
4721
+ /**
4722
+ * `clean` | `vulnerable` -- the verdict just recorded.
4723
+ */
4724
+ state: string;
4725
+ };
4726
+
4727
+ export type ProxyScanEntry = {
4728
+ cached_at: string;
4729
+ critical_count?: number | null;
4730
+ /**
4731
+ * SHA-256 of the cached bytes; NULL while the row is `pending_ingest`.
4732
+ */
4733
+ digest?: string | null;
4734
+ /**
4735
+ * The CVEs behind the counts (#3395), most severe first and bounded to
4736
+ * [`MAX_PROXY_FINDINGS`].
4737
+ *
4738
+ * Populated ONLY for a single-path (`?path=`) read, and only for a
4739
+ * `vulnerable` entry. Two reasons it is absent from the paged listing:
4740
+ * one query per row would make the list an N+1, and the listing is a
4741
+ * per-repository overview whose job is to point at the entry to open.
4742
+ *
4743
+ * `None` (omitted) means "not requested at this granularity"; an empty
4744
+ * vector means "requested, and this digest has no recorded detail" --
4745
+ * which is the real state for anything cached before #3395 shipped. The
4746
+ * two must stay distinguishable or a pre-#3395 artifact renders as having
4747
+ * no CVEs, which reads as clean.
4748
+ */
4749
+ findings?: Array<ProxyFinding> | null;
4750
+ findings_count?: number | null;
4751
+ high_count?: number | null;
4752
+ low_count?: number | null;
4753
+ max_severity?: string | null;
4754
+ medium_count?: number | null;
4755
+ /**
4756
+ * Set only when `state` is `not_scanned`.
4757
+ */
4758
+ not_scanned_reason?: string | null;
4759
+ path: string;
4760
+ /**
4761
+ * Floored at this repository's own `cached_at` -- see the module note.
4762
+ */
4763
+ scanned_at?: string | null;
4764
+ size_bytes: number;
4765
+ /**
4766
+ * `clean` | `vulnerable` | `not_scanned` | `pending_ingest`.
4767
+ */
4768
+ state: string;
4769
+ };
4770
+
4771
+ /**
4772
+ * Per-state counts over **distinct digests**, not paths: one repository can
4773
+ * cache the same digest at many paths, and the UI label must say so.
4774
+ */
4775
+ export type ProxyScanSummary = {
4776
+ clean: number;
4777
+ not_scanned: number;
4778
+ /**
4779
+ * Catalog rows whose `checksum_sha256` is still NULL. Counted as PATHS
4780
+ * (they have no digest to dedupe on) and excluded from every other count.
4781
+ */
4782
+ pending_ingest: number;
4783
+ /**
4784
+ * Distinct digests cached by this repository. Equals
4785
+ * `clean + vulnerable + not_scanned`.
4786
+ */
4787
+ total_digests: number;
4788
+ vulnerable: number;
4789
+ };
4790
+
4791
+ /**
4792
+ * One stored `proxy_scan_results` row, as returned by the admin
4793
+ * inspect/invalidate endpoints (#3244).
4794
+ */
4795
+ export type ProxyScanVerdictItem = {
4796
+ checksum_sha256: string;
4797
+ critical_count: number;
4798
+ findings_count: number;
4799
+ high_count: number;
4800
+ low_count: number;
4801
+ max_severity?: string | null;
4802
+ medium_count: number;
4803
+ scan_type: string;
4804
+ scanned_at: string;
4805
+ scanner_version?: string | null;
4806
+ verdict: string;
4807
+ };
4808
+
4809
+ /**
4810
+ * Response for the admin proxy-scan-verdict endpoints (#3244).
4811
+ */
4812
+ export type ProxyScanVerdictListResponse = {
4813
+ /**
4814
+ * The normalized (bare-hex) digest the verdicts are keyed on.
4815
+ */
4816
+ digest: string;
4817
+ verdicts: Array<ProxyScanVerdictItem>;
4818
+ };
4819
+
4820
+ export type ProxyScansResponse = {
4821
+ items: Array<ProxyScanEntry>;
4822
+ page: number;
4823
+ per_page: number;
4824
+ /**
4825
+ * `fail_open` | `fail_closed`. Lets `not_scanned` be read as "may have
4826
+ * been served unscanned" versus "was withheld".
4827
+ */
4828
+ proxy_scan_action: string;
4829
+ repository_key: string;
4830
+ /**
4831
+ * Enforcement context. Without it `vulnerable` is ambiguous: with
4832
+ * scanning on it means pulls are blocked; with scanning off it means the
4833
+ * artifact is served anyway and the verdict was recorded elsewhere.
4834
+ */
4835
+ scan_on_proxy: boolean;
4836
+ summary?: null | ProxyScanSummary;
4837
+ /**
4838
+ * Catalog paths matching the query (paths, not digests).
4839
+ */
4840
+ total: number;
4841
+ };
4842
+
4843
+ /**
4844
+ * Body for declaring that a locally-owned PyPI project tracks an upstream one.
4845
+ */
4846
+ export type PypiTrackRequest = {
4847
+ /**
4848
+ * Upstream Simple index project URL this local project tracks, e.g.
4849
+ * `https://pypi.org/simple/acme-sdk/`. Recorded and emitted as the PEP 708
4850
+ * `tracks` value.
4851
+ */
4852
+ tracks_url: string;
4853
+ };
4854
+
4855
+ /**
4856
+ * A single PEP 708 `tracks` declaration.
4857
+ */
4858
+ export type PypiTrackResponse = {
4859
+ /**
4860
+ * PEP 503 normalized project name.
4861
+ */
4862
+ normalized_name: string;
4863
+ repository_key: string;
4864
+ tracks_url: string;
4865
+ };
4866
+
4867
+ /**
4868
+ * All `tracks` declarations on a repository.
4869
+ */
4870
+ export type PypiTracksListResponse = {
4871
+ items: Array<PypiTrackResponse>;
4872
+ };
4873
+
4874
+ /**
4875
+ * Paginated admin quality-check list response (#2419).
4876
+ */
4877
+ export type QualityCheckListResponse = {
4878
+ items: Array<CheckResponse>;
4879
+ page: number;
4880
+ per_page: number;
4881
+ total: number;
4882
+ };
4883
+
4884
+ export type QuarantineActionResponse = {
4885
+ artifact_id: string;
4886
+ message: string;
4887
+ new_status: string;
4888
+ };
4889
+
4890
+ export type QuarantineNowRequest = {
4891
+ /**
4892
+ * Reason shown to developers whose downloads are blocked.
4893
+ */
4894
+ reason?: string | null;
4895
+ };
4896
+
4897
+ export type QuarantineStatusResponse = {
4898
+ artifact_id: string;
4899
+ is_blocked: boolean;
4900
+ /**
4901
+ * Why the artifact is held, when one was recorded by a scan policy or an
4902
+ * admin. This is the only surface that discloses the reason: blocked
4903
+ * downloads return a generic message because they are reachable
4904
+ * anonymously on public repositories (#2912).
4905
+ */
4906
+ quarantine_reason?: string | null;
4907
+ quarantine_status?: string | null;
4908
+ quarantine_until?: string | null;
4909
+ };
4910
+
4911
+ export type QuickSearchResponse = {
4912
+ results: Array<SearchResultItem>;
4913
+ };
4914
+
4915
+ export type ReEvaluateRequest = {
3942
4916
  default_action: string;
3943
4917
  staging_repo_id: string;
3944
4918
  };
@@ -4025,6 +4999,15 @@ export type RemoveProjectMemberRequest = {
4025
4999
  principal_type: string;
4026
5000
  };
4027
5001
 
5002
+ export type RenderImageBuildRequest = {
5003
+ spec: ImageBuildSpec;
5004
+ };
5005
+
5006
+ export type RenderImageBuildResponse = {
5007
+ containerfile: string;
5008
+ warnings: Array<string>;
5009
+ };
5010
+
4028
5011
  /**
4029
5012
  * Repository exposure descriptor echoed in the response.
4030
5013
  */
@@ -4249,6 +5232,16 @@ export type RepositoryStorageBreakdown = {
4249
5232
  download_count: number;
4250
5233
  format: string;
4251
5234
  last_upload_at?: string | null;
5235
+ /**
5236
+ * The proxy-cache half of `artifact_count` / `storage_bytes`, read from
5237
+ * `proxy_cache_artifacts` (those rows never appear in `artifacts`, #1280).
5238
+ * Disjoint from the hosted figures above, which exclude the legacy
5239
+ * backfilled `proxy-cache/%` `artifacts` rows the same way
5240
+ * `repository_usage_ledger.hosted_bytes` does (migration 182) — unlike
5241
+ * `StorageSnapshot::proxy_storage_bytes`, which is a breakdown of a total
5242
+ * that already contains it. Defaults to 0 on older payloads.
5243
+ */
5244
+ proxy_artifact_count?: number;
4252
5245
  /**
4253
5246
  * Downloads served by this repository's remote pull-through proxy
4254
5247
  * (`proxy_download_statistics`, #2537/#2704). Proxy-cached objects carry
@@ -4258,6 +5251,7 @@ export type RepositoryStorageBreakdown = {
4258
5251
  * unaffected; defaults to 0 when deserializing older payloads.
4259
5252
  */
4260
5253
  proxy_download_count?: number;
5254
+ proxy_storage_bytes?: number;
4261
5255
  repository_id: string;
4262
5256
  repository_key: string;
4263
5257
  repository_name: string;
@@ -4274,6 +5268,12 @@ export type RepositoryStorageBreakdown = {
4274
5268
  *
4275
5269
  * Quota is unaffected: these numbers are accounting/visibility only and do NOT
4276
5270
  * change how the repository's storage quota is enforced (#2056 §7).
5271
+ *
5272
+ * Known bounded exclusion: OCI *manifest* JSON objects are not weighed. Their
5273
+ * `artifacts.size_bytes` holds the aggregate image size, not the stored
5274
+ * object, so counting it would double the layer bytes (#3286); no column holds
5275
+ * the manifest's true size. Manifests are a few KB each, so every figure below
5276
+ * under-reports by roughly that much per tag (#3618).
4277
5277
  */
4278
5278
  export type RepositoryStorageStatsResponse = {
4279
5279
  /**
@@ -4419,6 +5419,18 @@ export type ResetPasswordResponse = {
4419
5419
  };
4420
5420
 
4421
5421
  export type RestoreRequest = {
5422
+ /**
5423
+ * Accept an archive whose integrity cannot be established (#3373).
5424
+ *
5425
+ * A restore refuses an archive it cannot check: since #3373 every backup
5426
+ * records its payload checksum on the `backups` row, outside the archive,
5427
+ * and the archive's contents are verified against it before any row is
5428
+ * ingested. Archives captured before that column existed fall back to the
5429
+ * checksum in their own manifest; one carrying neither cannot be verified
5430
+ * at all, and this flag is the deliberate, audited way to restore it
5431
+ * anyway. It never waives a checksum that is present and does not match.
5432
+ */
5433
+ allow_unverified_archive?: boolean;
4422
5434
  restore_artifacts?: boolean | null;
4423
5435
  restore_database?: boolean | null;
4424
5436
  target_repository_id?: string | null;
@@ -4427,6 +5439,13 @@ export type RestoreRequest = {
4427
5439
  export type RestoreResponse = {
4428
5440
  artifacts_restored: number;
4429
5441
  errors: Array<string>;
5442
+ /**
5443
+ * What the archive's contents were checked against (#3373):
5444
+ * `recorded` (the digest on the `backups` row, the strong case),
5445
+ * `manifest` (the archive's own checksum -- detects corruption, not
5446
+ * tampering), or `waived` (`allow_unverified_archive` was set).
5447
+ */
5448
+ integrity_anchor: string;
4430
5449
  tables_restored: Array<string>;
4431
5450
  };
4432
5451
 
@@ -4568,6 +5587,12 @@ export type SamlConfigResponse = {
4568
5587
  require_signed_assertions: boolean;
4569
5588
  sign_requests: boolean;
4570
5589
  slo_url?: string | null;
5590
+ /**
5591
+ * URL-safe alias the public SAML routes accept in place of `id`
5592
+ * (migration 218, #2583). `None` when the configuration has not been
5593
+ * given one; it is then addressable by `id` only.
5594
+ */
5595
+ slug?: string | null;
4571
5596
  sp_entity_id: string;
4572
5597
  sso_url: string;
4573
5598
  updated_at: string;
@@ -4605,8 +5630,10 @@ export type SbomResponse = {
4605
5630
 
4606
5631
  export type ScanConfigResponse = {
4607
5632
  /**
4608
- * Persisted and returned, but not currently consulted by any enforcement
4609
- * gate — blocking is configured via scan policies instead (#3144/#3246).
5633
+ * Opt-in that makes `severity_threshold` enforced on the proxy/OCI
5634
+ * inline scan gate (#3243/#3246). When false (default), the gate blocks
5635
+ * on any finding above `info`. Hosted-artifact blocking remains
5636
+ * configured via scan policies.
4610
5637
  */
4611
5638
  block_on_policy_violation: boolean;
4612
5639
  created_at: string;
@@ -4621,8 +5648,9 @@ export type ScanConfigResponse = {
4621
5648
  scan_on_proxy: boolean;
4622
5649
  scan_on_upload: boolean;
4623
5650
  /**
4624
- * Persisted and returned, but not currently consulted by any enforcement
4625
- * gate (#3243).
5651
+ * Severity floor for the inline proxy scan gate; live only when
5652
+ * `block_on_policy_violation` is set (#3243/#3246). Findings at or above
5653
+ * it block the pull.
4626
5654
  */
4627
5655
  severity_threshold: string;
4628
5656
  updated_at: string;
@@ -5004,12 +6032,23 @@ export type StatusCount = {
5004
6032
 
5005
6033
  /**
5006
6034
  * Request body for storage GC.
6035
+ *
6036
+ * `dry_run` is **required** and unknown fields are **rejected** (#3501): a
6037
+ * live GC pass is irreversible (no tombstone, no restore path short of a
6038
+ * backup), so an ambiguous request must fail loudly instead of selecting the
6039
+ * destructive branch. Before this, `{}` and any typo'd key
6040
+ * (`{"dryRun": true}`, `{"dry_Run": true}`) silently deserialized to
6041
+ * `dry_run: false` and performed a real deletion. Callers now say which pass
6042
+ * they mean: `{"dry_run": true}` to estimate, `{"dry_run": false}` to
6043
+ * delete; anything else is refused with an error naming the missing or
6044
+ * unknown field (axum's `Json` rejection, HTTP 422), and nothing is deleted.
5007
6045
  */
5008
6046
  export type StorageGcRequest = {
5009
6047
  /**
5010
6048
  * When true, report what would be deleted without actually deleting.
6049
+ * Required: an absent field is a rejected request, never a live delete.
5011
6050
  */
5012
- dry_run?: boolean;
6051
+ dry_run: boolean;
5013
6052
  };
5014
6053
 
5015
6054
  /**
@@ -5020,6 +6059,15 @@ export type StorageGcResult = {
5020
6059
  bytes_freed: number;
5021
6060
  dry_run: boolean;
5022
6061
  errors: Array<string>;
6062
+ /**
6063
+ * Orphaned row-less Maven flat objects this pass identified but left in
6064
+ * place because the sweep is not opted in (`MAVEN_FLAT_GC_ENABLED`
6065
+ * unset, #3431). Report-only: these objects and their attribution rows
6066
+ * were NOT deleted and are not counted in `storage_keys_deleted`. Always
6067
+ * `0` on a dry run (a dry run deletes nothing anyway) and when the sweep
6068
+ * is enabled.
6069
+ */
6070
+ maven_flat_objects_gated?: number;
5023
6071
  storage_keys_deleted: number;
5024
6072
  };
5025
6073
 
@@ -5027,6 +6075,28 @@ export type StorageGcResult = {
5027
6075
  * A single day's storage metrics snapshot.
5028
6076
  */
5029
6077
  export type StorageSnapshot = {
6078
+ /**
6079
+ * Proxy-cached objects at snapshot time (migration 210). They carry no
6080
+ * `artifacts` row (#1280), so this is disjoint from `total_artifacts`.
6081
+ * 0 for snapshots taken before migration 210 and on older payloads.
6082
+ */
6083
+ proxy_artifact_count?: number;
6084
+ /**
6085
+ * Pull-through serves, recorded in `proxy_download_statistics` rather
6086
+ * than `download_statistics`, so this is disjoint from `total_downloads`.
6087
+ */
6088
+ proxy_download_count?: number;
6089
+ /**
6090
+ * Bytes held by those objects — a *breakdown* of `total_storage_bytes`
6091
+ * above, not a disjoint bucket: that total sums
6092
+ * `repository_usage_ledger (hosted_bytes + proxy_bytes + oci_bytes)` and
6093
+ * migration 182 defines `proxy_bytes` as exactly this sum, so the two
6094
+ * must not be added. Same contract as the identically named
6095
+ * `/admin/stats` field (#3134/#3249). (On `RepositoryStorageBreakdown`
6096
+ * the same field name IS disjoint from that struct's `storage_bytes`,
6097
+ * which is hosted-only.)
6098
+ */
6099
+ proxy_storage_bytes?: number;
5030
6100
  snapshot_date: string;
5031
6101
  /**
5032
6102
  * Rows in `artifacts` (for OCI repositories that is manifests only —
@@ -5232,11 +6302,11 @@ export type SyncTriggerResponse = {
5232
6302
  * affordances a caller needs *before* authenticating (upload limit, demo
5233
6303
  * mode, whether guest access and which login providers are available).
5234
6304
  * * **Security-posture fields** (`scanners`, `search_engine`,
5235
- * `storage_backend`, `permissions`, `plugin_signing`) describe the
5236
- * instance's defensive configuration. They are returned **only to
5237
- * authenticated admins** and are omitted for anonymous / non-admin callers,
5238
- * so the deployment's security posture cannot be fingerprinted by an
5239
- * unauthenticated attacker.
6305
+ * `storage_backend`, `permissions`, `plugin_signing`, and
6306
+ * `auth.admin_break_glass_enabled`) describe the instance's defensive
6307
+ * configuration. They are returned **only to authenticated admins** and are
6308
+ * omitted for anonymous / non-admin callers, so the deployment's security
6309
+ * posture cannot be fingerprinted by an unauthenticated attacker.
5240
6310
  */
5241
6311
  export type SystemConfigResponse = {
5242
6312
  /**
@@ -5301,11 +6371,19 @@ export type SystemStats = {
5301
6371
  active_peers: number;
5302
6372
  pending_sync_tasks: number;
5303
6373
  /**
5304
- * Proxy-cached (pull-through) objects, tracked in `proxy_cache_artifacts`
5305
- * rather than `artifacts`. Since #3134 the byte figure is a breakdown of
5306
- * `total_storage_bytes` (do not add the two).
6374
+ * Count of proxy-cached (pull-through) objects, tracked in
6375
+ * `proxy_cache_artifacts` rather than `artifacts`. This COUNT is disjoint
6376
+ * from `total_artifacts`, which reads only the hosted tables.
5307
6377
  */
5308
6378
  proxy_artifact_count: number;
6379
+ /**
6380
+ * Bytes held by proxy-cached objects. Since #3134 this is a **breakdown
6381
+ * of** `total_storage_bytes`, not a disjoint bucket: the ledger's
6382
+ * `proxy_bytes` component is already inside that total, so a dashboard
6383
+ * that adds the two double-counts the cache (#3650). The count above and
6384
+ * the bytes here therefore do NOT compose the same way — only the count
6385
+ * is disjoint.
6386
+ */
5309
6387
  proxy_storage_bytes: number;
5310
6388
  /**
5311
6389
  * Rows in `artifacts` (for OCI repositories that is manifests only —
@@ -5431,6 +6509,45 @@ export type TokenListResponse = {
5431
6509
  items: Array<TokenInfoResponse>;
5432
6510
  };
5433
6511
 
6512
+ /**
6513
+ * Current API token expiration policy plus the inventory an operator needs
6514
+ * before (or after) tightening it: how many live tokens already exist with
6515
+ * no expiration. Enabling the policy never touches those rows — they are
6516
+ * surfaced here so an administrator can rotate them deliberately.
6517
+ */
6518
+ export type TokenPolicyResponse = {
6519
+ /**
6520
+ * Whether `PUT` can change the policy at all right now.
6521
+ */
6522
+ editable: boolean;
6523
+ /**
6524
+ * Live never-expiring tokens held by service accounts (CI credentials —
6525
+ * exempt from enforcement unless `apply_to_service_accounts` is set).
6526
+ */
6527
+ non_expiring_service_account_tokens: number;
6528
+ /**
6529
+ * Live (unrevoked, active-owner) never-expiring tokens held by regular
6530
+ * users. These predate or bypass the policy and are unaffected by it;
6531
+ * rotate them via the existing token-revocation endpoints.
6532
+ */
6533
+ non_expiring_user_tokens: number;
6534
+ /**
6535
+ * The policy in force.
6536
+ */
6537
+ policy: ApiTokenExpiryPolicy;
6538
+ /**
6539
+ * Whether it comes from the `API_TOKEN_EXPIRATION_*` environment
6540
+ * variables (in which case `PUT` is refused) or from the database.
6541
+ */
6542
+ source: TokenPolicySource;
6543
+ };
6544
+
6545
+ /**
6546
+ * Where the effective policy came from, surfaced on the admin read endpoint
6547
+ * so an operator can tell why a `PUT` is refused.
6548
+ */
6549
+ export type TokenPolicySource = 'environment' | 'database';
6550
+
5434
6551
  export type TotpCodeRequest = {
5435
6552
  code: string;
5436
6553
  };
@@ -5444,6 +6561,104 @@ export type TotpEnableResponse = {
5444
6561
  backup_codes: Array<string>;
5445
6562
  };
5446
6563
 
6564
+ /**
6565
+ * Request body completing forced enrollment.
6566
+ */
6567
+ export type TotpEnrollCompleteRequest = {
6568
+ /**
6569
+ * The current 6-digit code from the authenticator that scanned the secret.
6570
+ */
6571
+ code: string;
6572
+ /**
6573
+ * The `totp_token` returned alongside `totp_enrollment_required: true`.
6574
+ */
6575
+ totp_token: string;
6576
+ };
6577
+
6578
+ /**
6579
+ * Successful forced enrollment: a real session *plus* the backup codes.
6580
+ *
6581
+ * The session is returned here, in the same response that completes
6582
+ * enrollment, so a user subject to the policy is never left holding a valid
6583
+ * password and no way in.
6584
+ */
6585
+ export type TotpEnrollCompleteResponse = {
6586
+ access_token: string;
6587
+ /**
6588
+ * One-time recovery codes. Shown exactly once — they are stored hashed.
6589
+ */
6590
+ backup_codes: Array<string>;
6591
+ expires_in: number;
6592
+ must_change_password: boolean;
6593
+ refresh_token: string;
6594
+ token_type: string;
6595
+ };
6596
+
6597
+ /**
6598
+ * Request body carrying an enrollment ticket issued by `POST /auth/login`.
6599
+ */
6600
+ export type TotpEnrollSetupRequest = {
6601
+ /**
6602
+ * The `totp_token` returned alongside `totp_enrollment_required: true`.
6603
+ */
6604
+ totp_token: string;
6605
+ };
6606
+
6607
+ /**
6608
+ * System-wide 2FA enforcement policy.
6609
+ */
6610
+ export type TotpPolicy = 'disabled' | 'required_for_admins' | 'required_for_all';
6611
+
6612
+ /**
6613
+ * Current 2FA enforcement policy plus the context an operator needs before
6614
+ * tightening it.
6615
+ */
6616
+ export type TotpPolicyResponse = {
6617
+ /**
6618
+ * Whether the *calling* administrator has TOTP enabled. Tightening the
6619
+ * policy requires this.
6620
+ */
6621
+ caller_totp_enabled: boolean;
6622
+ /**
6623
+ * Whether `PUT` can change the policy at all right now.
6624
+ */
6625
+ editable: boolean;
6626
+ /**
6627
+ * Local (password-authenticating, non-service) administrators.
6628
+ */
6629
+ local_admins: number;
6630
+ /**
6631
+ * How many of those already have TOTP enabled. Under
6632
+ * `required_for_admins`, `local_admins - local_admins_with_totp` is the
6633
+ * number of administrators who will be sent through forced enrollment at
6634
+ * their next sign-in.
6635
+ */
6636
+ local_admins_with_totp: number;
6637
+ /**
6638
+ * Local (password-authenticating, non-service) users, admins included.
6639
+ */
6640
+ local_users: number;
6641
+ /**
6642
+ * How many of those already have TOTP enabled.
6643
+ */
6644
+ local_users_with_totp: number;
6645
+ /**
6646
+ * The policy in force.
6647
+ */
6648
+ policy: TotpPolicy;
6649
+ /**
6650
+ * Whether it comes from the `TOTP_POLICY` environment variable (in which
6651
+ * case `PUT` is refused) or from the database.
6652
+ */
6653
+ source: TotpPolicySource;
6654
+ };
6655
+
6656
+ /**
6657
+ * Where the effective policy came from, surfaced on the admin read endpoint so
6658
+ * an operator can tell why a `PUT` is refused.
6659
+ */
6660
+ export type TotpPolicySource = 'environment' | 'database';
6661
+
5447
6662
  export type TotpSetupResponse = {
5448
6663
  qr_code_url: string;
5449
6664
  secret: string;
@@ -5655,6 +6870,15 @@ export type UpdateLifecyclePolicyRequest = {
5655
6870
  };
5656
6871
 
5657
6872
  export type UpdateOidcConfigRequest = {
6873
+ /**
6874
+ * IdP group whose members are granted the admin role on login. `Some`
6875
+ * sets `attribute_mapping.admin_group` after the mapping merge/replace
6876
+ * above is applied; `None` leaves the mapping-derived value alone — so
6877
+ * `None` together with `attribute_mapping_replace` clears it, which is
6878
+ * how the env bootstrap revokes group-based admin when
6879
+ * `OIDC_ADMIN_GROUP` is unset (#3420).
6880
+ */
6881
+ admin_group?: string | null;
5658
6882
  allow_legacy_rsa_keys?: boolean | null;
5659
6883
  /**
5660
6884
  * Partial update for `attribute_mapping`. Keys present in this object
@@ -5824,7 +7048,7 @@ export type UpdateRepositoryRequest = {
5824
7048
  * Update the PyPI simple-index prefix (stored in `repository_config` under
5825
7049
  * `pypi_upstream_index_path`). Pass `""` for flat CDN layout, `"simple"` to
5826
7050
  * restore the PEP 503 default, or any other non-empty string for a custom prefix.
5827
- * Only meaningful for PyPI / Poetry / Conda Remote repositories.
7051
+ * Only meaningful for PyPI / Poetry / Jupyter / Conda Remote repositories.
5828
7052
  */
5829
7053
  pypi_upstream_index_path?: string | null;
5830
7054
  /**
@@ -5889,6 +7113,14 @@ export type UpdateSamlConfigRequest = {
5889
7113
  require_signed_assertions?: boolean | null;
5890
7114
  sign_requests?: boolean | null;
5891
7115
  slo_url?: string | null;
7116
+ /**
7117
+ * Set or change the URL-safe alias (#2583). Omitting it preserves the
7118
+ * current value, matching how `slo_url` and `admin_group` behave; a
7119
+ * slug therefore cannot be cleared through this endpoint, only
7120
+ * replaced, so an ACS URL an IdP is already configured with cannot be
7121
+ * removed by an update that simply forgot to mention it.
7122
+ */
7123
+ slug?: string | null;
5892
7124
  sp_entity_id?: string | null;
5893
7125
  sso_url?: string | null;
5894
7126
  use_absolute_acs_url?: boolean | null;
@@ -5924,8 +7156,22 @@ export type UpdateSyncPolicyPayload = {
5924
7156
  };
5925
7157
  };
5926
7158
 
5927
- export type UpdateUserRequest = {
5928
- display_name?: string | null;
7159
+ /**
7160
+ * Request body for `PUT /admin/settings/token-policy`.
7161
+ */
7162
+ export type UpdateTokenPolicyRequest = {
7163
+ policy: ApiTokenExpiryPolicy;
7164
+ };
7165
+
7166
+ /**
7167
+ * Request body for `PUT /admin/settings/totp-policy`.
7168
+ */
7169
+ export type UpdateTotpPolicyRequest = {
7170
+ policy: TotpPolicy;
7171
+ };
7172
+
7173
+ export type UpdateUserRequest = {
7174
+ display_name?: string | null;
5929
7175
  email?: string | null;
5930
7176
  is_active?: boolean | null;
5931
7177
  is_admin?: boolean | null;
@@ -5978,8 +7224,8 @@ export type UpsertLicensePolicyRequest = {
5978
7224
  */
5979
7225
  export type UpsertScanConfigRequest = {
5980
7226
  /**
5981
- * Accepted and persisted, but consulted by no gate — enforcement is the
5982
- * `scan_policies` table's job (#3144; disposition tracked in #3246).
7227
+ * Opt-in that makes `severity_threshold` enforced on the proxy/OCI
7228
+ * inline scan gate (#3243/#3246). Default false = block on any finding.
5983
7229
  */
5984
7230
  block_on_policy_violation?: boolean | null;
5985
7231
  /**
@@ -5991,16 +7237,19 @@ export type UpsertScanConfigRequest = {
5991
7237
  scan_on_proxy?: boolean | null;
5992
7238
  scan_on_upload?: boolean | null;
5993
7239
  /**
5994
- * Accepted and persisted, but consulted by no production gate (#3243).
7240
+ * Severity floor for the inline proxy scan gate, live only when
7241
+ * `block_on_policy_violation` is set (#3243/#3246).
5995
7242
  */
5996
7243
  severity_threshold?: string | null;
5997
7244
  };
5998
7245
 
5999
7246
  export type UpstreamAuthRequest = {
6000
7247
  /**
6001
- * Auth type: "basic", "bearer", or "none" to remove.
7248
+ * Auth type: "basic", "bearer", "aws_ecr", "aws_codeartifact", or "none"
7249
+ * to remove.
6002
7250
  */
6003
7251
  auth_type: string;
7252
+ aws?: null | AwsUpstreamAuthRequest;
6004
7253
  /**
6005
7254
  * Password (basic) or token (bearer). Write-only, never returned.
6006
7255
  */
@@ -6626,6 +7875,10 @@ export type RestoreBackupData = {
6626
7875
  };
6627
7876
 
6628
7877
  export type RestoreBackupErrors = {
7878
+ /**
7879
+ * Archive integrity could not be established, or an unsupported option was supplied
7880
+ */
7881
+ 400: unknown;
6629
7882
  /**
6630
7883
  * Backup not found
6631
7884
  */
@@ -7522,6 +8775,115 @@ export type GetHealthLogResponses = {
7522
8775
 
7523
8776
  export type GetHealthLogResponse = GetHealthLogResponses[keyof GetHealthLogResponses];
7524
8777
 
8778
+ export type BackfillPackagesData = {
8779
+ body?: never;
8780
+ path?: never;
8781
+ query?: {
8782
+ /**
8783
+ * Restrict the walk to one repository. Omit to walk every hosted
8784
+ * repository in a catalog-eligible format.
8785
+ */
8786
+ repository_key?: string | null;
8787
+ };
8788
+ url: '/api/v1/admin/packages/backfill';
8789
+ };
8790
+
8791
+ export type BackfillPackagesErrors = {
8792
+ /**
8793
+ * Admin privileges required
8794
+ */
8795
+ 401: unknown;
8796
+ /**
8797
+ * Repository not found
8798
+ */
8799
+ 404: unknown;
8800
+ /**
8801
+ * Internal server error
8802
+ */
8803
+ 500: unknown;
8804
+ };
8805
+
8806
+ export type BackfillPackagesResponses = {
8807
+ /**
8808
+ * Backfill completed
8809
+ */
8810
+ 200: PackagesBackfillResponse;
8811
+ };
8812
+
8813
+ export type BackfillPackagesResponse = BackfillPackagesResponses[keyof BackfillPackagesResponses];
8814
+
8815
+ export type DeleteProxyScanVerdictsData = {
8816
+ body?: never;
8817
+ path: {
8818
+ /**
8819
+ * Content digest: `sha256:<64 hex>` or bare 64-hex
8820
+ */
8821
+ digest: string;
8822
+ };
8823
+ query?: never;
8824
+ url: '/api/v1/admin/proxy-scan-verdicts/{digest}';
8825
+ };
8826
+
8827
+ export type DeleteProxyScanVerdictsErrors = {
8828
+ /**
8829
+ * Malformed digest
8830
+ */
8831
+ 400: unknown;
8832
+ /**
8833
+ * Admin privileges required
8834
+ */
8835
+ 403: unknown;
8836
+ /**
8837
+ * No stored verdict for this digest
8838
+ */
8839
+ 404: unknown;
8840
+ };
8841
+
8842
+ export type DeleteProxyScanVerdictsResponses = {
8843
+ /**
8844
+ * Deleted verdict rows (re-assessment forced on next pull)
8845
+ */
8846
+ 200: ProxyScanVerdictListResponse;
8847
+ };
8848
+
8849
+ export type DeleteProxyScanVerdictsResponse = DeleteProxyScanVerdictsResponses[keyof DeleteProxyScanVerdictsResponses];
8850
+
8851
+ export type GetProxyScanVerdictsData = {
8852
+ body?: never;
8853
+ path: {
8854
+ /**
8855
+ * Content digest: `sha256:<64 hex>` or bare 64-hex
8856
+ */
8857
+ digest: string;
8858
+ };
8859
+ query?: never;
8860
+ url: '/api/v1/admin/proxy-scan-verdicts/{digest}';
8861
+ };
8862
+
8863
+ export type GetProxyScanVerdictsErrors = {
8864
+ /**
8865
+ * Malformed digest
8866
+ */
8867
+ 400: unknown;
8868
+ /**
8869
+ * Admin privileges required
8870
+ */
8871
+ 403: unknown;
8872
+ /**
8873
+ * No stored verdict for this digest
8874
+ */
8875
+ 404: unknown;
8876
+ };
8877
+
8878
+ export type GetProxyScanVerdictsResponses = {
8879
+ /**
8880
+ * Stored verdict rows for the digest
8881
+ */
8882
+ 200: ProxyScanVerdictListResponse;
8883
+ };
8884
+
8885
+ export type GetProxyScanVerdictsResponse = GetProxyScanVerdictsResponses[keyof GetProxyScanVerdictsResponses];
8886
+
7525
8887
  export type AdminListChecksData = {
7526
8888
  body?: never;
7527
8889
  path?: never;
@@ -7888,6 +9250,118 @@ export type UpdateSettingsResponses = {
7888
9250
 
7889
9251
  export type UpdateSettingsResponse = UpdateSettingsResponses[keyof UpdateSettingsResponses];
7890
9252
 
9253
+ export type GetTokenPolicyData = {
9254
+ body?: never;
9255
+ path?: never;
9256
+ query?: never;
9257
+ url: '/api/v1/admin/settings/token-policy';
9258
+ };
9259
+
9260
+ export type GetTokenPolicyErrors = {
9261
+ /**
9262
+ * Admin privileges required
9263
+ */
9264
+ 403: ErrorResponse;
9265
+ };
9266
+
9267
+ export type GetTokenPolicyError = GetTokenPolicyErrors[keyof GetTokenPolicyErrors];
9268
+
9269
+ export type GetTokenPolicyResponses = {
9270
+ /**
9271
+ * Current API token expiration policy
9272
+ */
9273
+ 200: TokenPolicyResponse;
9274
+ };
9275
+
9276
+ export type GetTokenPolicyResponse = GetTokenPolicyResponses[keyof GetTokenPolicyResponses];
9277
+
9278
+ export type UpdateTokenPolicyData = {
9279
+ body: UpdateTokenPolicyRequest;
9280
+ path?: never;
9281
+ query?: never;
9282
+ url: '/api/v1/admin/settings/token-policy';
9283
+ };
9284
+
9285
+ export type UpdateTokenPolicyErrors = {
9286
+ /**
9287
+ * Inconsistent policy (range/default contradiction)
9288
+ */
9289
+ 400: ErrorResponse;
9290
+ /**
9291
+ * Admin privileges required
9292
+ */
9293
+ 403: ErrorResponse;
9294
+ /**
9295
+ * Refused: policy pinned by API_TOKEN_EXPIRATION_* environment variables
9296
+ */
9297
+ 409: ErrorResponse;
9298
+ };
9299
+
9300
+ export type UpdateTokenPolicyError = UpdateTokenPolicyErrors[keyof UpdateTokenPolicyErrors];
9301
+
9302
+ export type UpdateTokenPolicyResponses = {
9303
+ /**
9304
+ * Policy updated
9305
+ */
9306
+ 200: TokenPolicyResponse;
9307
+ };
9308
+
9309
+ export type UpdateTokenPolicyResponse = UpdateTokenPolicyResponses[keyof UpdateTokenPolicyResponses];
9310
+
9311
+ export type GetTotpPolicyData = {
9312
+ body?: never;
9313
+ path?: never;
9314
+ query?: never;
9315
+ url: '/api/v1/admin/settings/totp-policy';
9316
+ };
9317
+
9318
+ export type GetTotpPolicyErrors = {
9319
+ /**
9320
+ * Admin privileges required
9321
+ */
9322
+ 403: ErrorResponse;
9323
+ };
9324
+
9325
+ export type GetTotpPolicyError = GetTotpPolicyErrors[keyof GetTotpPolicyErrors];
9326
+
9327
+ export type GetTotpPolicyResponses = {
9328
+ /**
9329
+ * Current 2FA enforcement policy
9330
+ */
9331
+ 200: TotpPolicyResponse;
9332
+ };
9333
+
9334
+ export type GetTotpPolicyResponse = GetTotpPolicyResponses[keyof GetTotpPolicyResponses];
9335
+
9336
+ export type UpdateTotpPolicyData = {
9337
+ body: UpdateTotpPolicyRequest;
9338
+ path?: never;
9339
+ query?: never;
9340
+ url: '/api/v1/admin/settings/totp-policy';
9341
+ };
9342
+
9343
+ export type UpdateTotpPolicyErrors = {
9344
+ /**
9345
+ * Admin privileges required
9346
+ */
9347
+ 403: ErrorResponse;
9348
+ /**
9349
+ * Refused: policy pinned by TOTP_POLICY, or the calling admin has not enrolled in TOTP
9350
+ */
9351
+ 409: ErrorResponse;
9352
+ };
9353
+
9354
+ export type UpdateTotpPolicyError = UpdateTotpPolicyErrors[keyof UpdateTotpPolicyErrors];
9355
+
9356
+ export type UpdateTotpPolicyResponses = {
9357
+ /**
9358
+ * Policy updated
9359
+ */
9360
+ 200: TotpPolicyResponse;
9361
+ };
9362
+
9363
+ export type UpdateTotpPolicyResponse = UpdateTotpPolicyResponses[keyof UpdateTotpPolicyResponses];
9364
+
7891
9365
  export type SendTestEmailData = {
7892
9366
  body: SmtpTestRequest;
7893
9367
  path?: never;
@@ -8608,6 +10082,33 @@ export type OciBlobReportResponses = {
8608
10082
 
8609
10083
  export type OciBlobReportResponse = OciBlobReportResponses[keyof OciBlobReportResponses];
8610
10084
 
10085
+ export type BackfillStorageLedgerData = {
10086
+ body?: never;
10087
+ path?: never;
10088
+ query?: never;
10089
+ url: '/api/v1/admin/storage/ledger/backfill';
10090
+ };
10091
+
10092
+ export type BackfillStorageLedgerErrors = {
10093
+ /**
10094
+ * Admin privileges required
10095
+ */
10096
+ 401: unknown;
10097
+ /**
10098
+ * Internal server error
10099
+ */
10100
+ 500: unknown;
10101
+ };
10102
+
10103
+ export type BackfillStorageLedgerResponses = {
10104
+ /**
10105
+ * Ledger recomputed
10106
+ */
10107
+ 200: LedgerBackfillResponse;
10108
+ };
10109
+
10110
+ export type BackfillStorageLedgerResponse = BackfillStorageLedgerResponses[keyof BackfillStorageLedgerResponses];
10111
+
8611
10112
  export type ListCrashesData = {
8612
10113
  body?: never;
8613
10114
  path?: never;
@@ -9143,6 +10644,9 @@ export type GetArtifactStatsResponses = {
9143
10644
  export type GetArtifactStatsResponse = GetArtifactStatsResponses[keyof GetArtifactStatsResponses];
9144
10645
 
9145
10646
  export type ExchangeCiTokenData = {
10647
+ /**
10648
+ * Optional. Omit the body entirely to resolve the provider from the assertion's iss claim; send provider_id only to override that.
10649
+ */
9146
10650
  body: CiTokenRequest;
9147
10651
  path?: never;
9148
10652
  query?: never;
@@ -9150,12 +10654,16 @@ export type ExchangeCiTokenData = {
9150
10654
  };
9151
10655
 
9152
10656
  export type ExchangeCiTokenErrors = {
10657
+ /**
10658
+ * Malformed body, provider_id disagrees with the assertion's iss, or the issuer matches several enabled providers
10659
+ */
10660
+ 400: ErrorResponse;
9153
10661
  /**
9154
10662
  * Invalid CI token or provider configuration
9155
10663
  */
9156
10664
  401: ErrorResponse;
9157
10665
  /**
9158
- * CI OIDC provider not found
10666
+ * No enabled CI OIDC provider matches the assertion's issuer
9159
10667
  */
9160
10668
  404: ErrorResponse;
9161
10669
  };
@@ -9360,11 +10868,24 @@ export type OidcLoginData = {
9360
10868
  */
9361
10869
  id: string;
9362
10870
  };
9363
- query?: never;
10871
+ query?: {
10872
+ /**
10873
+ * Optional OIDC `prompt` value forwarded to the IdP's authorization
10874
+ * endpoint. Only `none` is accepted (silent check-sso): the web UI uses
10875
+ * it to probe for an existing IdP session without ever rendering the
10876
+ * IdP's login page. Any other value is rejected so the login redirect
10877
+ * cannot be steered into unexpected IdP behaviours.
10878
+ */
10879
+ prompt?: string | null;
10880
+ };
9364
10881
  url: '/api/v1/auth/sso/oidc/{id}/login';
9365
10882
  };
9366
10883
 
9367
10884
  export type OidcLoginErrors = {
10885
+ /**
10886
+ * Unsupported prompt value
10887
+ */
10888
+ 400: ErrorResponse;
9368
10889
  /**
9369
10890
  * OIDC provider not found
9370
10891
  */
@@ -9393,7 +10914,7 @@ export type SamlAcsData = {
9393
10914
  body: SamlAcsForm;
9394
10915
  path: {
9395
10916
  /**
9396
- * SAML provider configuration ID
10917
+ * SAML provider configuration ID (UUID) or slug
9397
10918
  */
9398
10919
  id: string;
9399
10920
  };
@@ -9414,7 +10935,7 @@ export type SamlLoginData = {
9414
10935
  body?: never;
9415
10936
  path: {
9416
10937
  /**
9417
- * SAML provider configuration ID
10938
+ * SAML provider configuration ID (UUID) or slug
9418
10939
  */
9419
10940
  id: string;
9420
10941
  };
@@ -9529,6 +11050,10 @@ export type DisableTotpErrors = {
9529
11050
  * Invalid password or TOTP code
9530
11051
  */
9531
11052
  401: ErrorResponse;
11053
+ /**
11054
+ * The 2FA enforcement policy requires TOTP for this account
11055
+ */
11056
+ 409: ErrorResponse;
9532
11057
  };
9533
11058
 
9534
11059
  export type DisableTotpError = DisableTotpErrors[keyof DisableTotpErrors];
@@ -9565,6 +11090,64 @@ export type EnableTotpResponses = {
9565
11090
 
9566
11091
  export type EnableTotpResponse = EnableTotpResponses[keyof EnableTotpResponses];
9567
11092
 
11093
+ export type EnrollCompleteData = {
11094
+ body: TotpEnrollCompleteRequest;
11095
+ path?: never;
11096
+ query?: never;
11097
+ url: '/api/v1/auth/totp/enroll/complete';
11098
+ };
11099
+
11100
+ export type EnrollCompleteErrors = {
11101
+ /**
11102
+ * TOTP is already enabled, or /enroll/setup was not called first
11103
+ */
11104
+ 400: ErrorResponse;
11105
+ /**
11106
+ * Invalid code, or invalid/expired/already-used enrollment ticket
11107
+ */
11108
+ 401: ErrorResponse;
11109
+ };
11110
+
11111
+ export type EnrollCompleteError = EnrollCompleteErrors[keyof EnrollCompleteErrors];
11112
+
11113
+ export type EnrollCompleteResponses = {
11114
+ /**
11115
+ * TOTP enrolled; session and backup codes returned
11116
+ */
11117
+ 200: TotpEnrollCompleteResponse;
11118
+ };
11119
+
11120
+ export type EnrollCompleteResponse = EnrollCompleteResponses[keyof EnrollCompleteResponses];
11121
+
11122
+ export type EnrollSetupData = {
11123
+ body: TotpEnrollSetupRequest;
11124
+ path?: never;
11125
+ query?: never;
11126
+ url: '/api/v1/auth/totp/enroll/setup';
11127
+ };
11128
+
11129
+ export type EnrollSetupErrors = {
11130
+ /**
11131
+ * TOTP is already enabled for this account
11132
+ */
11133
+ 400: ErrorResponse;
11134
+ /**
11135
+ * Invalid or expired enrollment ticket
11136
+ */
11137
+ 401: ErrorResponse;
11138
+ };
11139
+
11140
+ export type EnrollSetupError = EnrollSetupErrors[keyof EnrollSetupErrors];
11141
+
11142
+ export type EnrollSetupResponses = {
11143
+ /**
11144
+ * TOTP secret and QR code URL for enrollment
11145
+ */
11146
+ 200: TotpSetupResponse;
11147
+ };
11148
+
11149
+ export type EnrollSetupResponse = EnrollSetupResponses[keyof EnrollSetupResponses];
11150
+
9568
11151
  export type SetupTotpData = {
9569
11152
  body?: never;
9570
11153
  path?: never;
@@ -11507,7 +13090,14 @@ export type GetPackageData = {
11507
13090
  */
11508
13091
  id: string;
11509
13092
  };
11510
- query?: never;
13093
+ query?: {
13094
+ /**
13095
+ * Optional repository key providing virtual-repo context. When it names a
13096
+ * virtual repo that contains this package, the returned `repository_key`
13097
+ * reports the virtual key (matching the aggregated listing).
13098
+ */
13099
+ repository_key?: string | null;
13100
+ };
11511
13101
  url: '/api/v1/packages/{id}';
11512
13102
  };
11513
13103
 
@@ -12148,9 +13738,9 @@ export type GetAssignedReposErrors = {
12148
13738
 
12149
13739
  export type GetAssignedReposResponses = {
12150
13740
  /**
12151
- * List of assigned repository IDs
13741
+ * Sync-enabled subscriptions for this peer (repo id + replication mode)
12152
13742
  */
12153
- 200: Array<string>;
13743
+ 200: Array<SubscriptionResponse>;
12154
13744
  };
12155
13745
 
12156
13746
  export type GetAssignedReposResponse = GetAssignedReposResponses[keyof GetAssignedReposResponses];
@@ -14801,6 +16391,82 @@ export type DownloadArtifactResponses = {
14801
16391
 
14802
16392
  export type DownloadArtifactResponse = DownloadArtifactResponses[keyof DownloadArtifactResponses];
14803
16393
 
16394
+ export type GetEgressProxyData = {
16395
+ body?: never;
16396
+ path: {
16397
+ /**
16398
+ * Repository key
16399
+ */
16400
+ key: string;
16401
+ };
16402
+ query?: never;
16403
+ url: '/api/v1/repositories/{key}/egress-proxy';
16404
+ };
16405
+
16406
+ export type GetEgressProxyErrors = {
16407
+ /**
16408
+ * Authentication required
16409
+ */
16410
+ 401: unknown;
16411
+ /**
16412
+ * Repository admin required
16413
+ */
16414
+ 403: unknown;
16415
+ /**
16416
+ * Repository not found
16417
+ */
16418
+ 404: unknown;
16419
+ };
16420
+
16421
+ export type GetEgressProxyResponses = {
16422
+ /**
16423
+ * Egress proxy configuration
16424
+ */
16425
+ 200: EgressProxyResponse;
16426
+ };
16427
+
16428
+ export type GetEgressProxyResponse = GetEgressProxyResponses[keyof GetEgressProxyResponses];
16429
+
16430
+ export type SetEgressProxyData = {
16431
+ body: EgressProxyRequest;
16432
+ path: {
16433
+ /**
16434
+ * Repository key
16435
+ */
16436
+ key: string;
16437
+ };
16438
+ query?: never;
16439
+ url: '/api/v1/repositories/{key}/egress-proxy';
16440
+ };
16441
+
16442
+ export type SetEgressProxyErrors = {
16443
+ /**
16444
+ * Invalid mode or proxy URL
16445
+ */
16446
+ 400: unknown;
16447
+ /**
16448
+ * Authentication required
16449
+ */
16450
+ 401: unknown;
16451
+ /**
16452
+ * Repository admin required
16453
+ */
16454
+ 403: unknown;
16455
+ /**
16456
+ * Repository not found
16457
+ */
16458
+ 404: unknown;
16459
+ };
16460
+
16461
+ export type SetEgressProxyResponses = {
16462
+ /**
16463
+ * Egress proxy updated
16464
+ */
16465
+ 200: EgressProxyResponse;
16466
+ };
16467
+
16468
+ export type SetEgressProxyResponse = SetEgressProxyResponses[keyof SetEgressProxyResponses];
16469
+
14804
16470
  export type ListSubscriptionsData = {
14805
16471
  body?: never;
14806
16472
  path: {
@@ -14810,112 +16476,336 @@ export type ListSubscriptionsData = {
14810
16476
  key: string;
14811
16477
  };
14812
16478
  query?: never;
14813
- url: '/api/v1/repositories/{key}/email-subscriptions';
16479
+ url: '/api/v1/repositories/{key}/email-subscriptions';
16480
+ };
16481
+
16482
+ export type ListSubscriptionsErrors = {
16483
+ /**
16484
+ * Not authenticated
16485
+ */
16486
+ 401: unknown;
16487
+ /**
16488
+ * Insufficient permissions
16489
+ */
16490
+ 403: unknown;
16491
+ /**
16492
+ * Repository not found
16493
+ */
16494
+ 404: unknown;
16495
+ };
16496
+
16497
+ export type ListSubscriptionsResponses = {
16498
+ /**
16499
+ * List of email subscriptions
16500
+ */
16501
+ 200: EmailSubscriptionListResponse;
16502
+ };
16503
+
16504
+ export type ListSubscriptionsResponse = ListSubscriptionsResponses[keyof ListSubscriptionsResponses];
16505
+
16506
+ export type CreateSubscriptionData = {
16507
+ body: CreateEmailSubscriptionRequest;
16508
+ path: {
16509
+ /**
16510
+ * Repository key
16511
+ */
16512
+ key: string;
16513
+ };
16514
+ query?: never;
16515
+ url: '/api/v1/repositories/{key}/email-subscriptions';
16516
+ };
16517
+
16518
+ export type CreateSubscriptionErrors = {
16519
+ /**
16520
+ * Validation error
16521
+ */
16522
+ 400: unknown;
16523
+ /**
16524
+ * Not authenticated
16525
+ */
16526
+ 401: unknown;
16527
+ /**
16528
+ * Insufficient permissions
16529
+ */
16530
+ 403: unknown;
16531
+ /**
16532
+ * Repository not found
16533
+ */
16534
+ 404: unknown;
16535
+ };
16536
+
16537
+ export type CreateSubscriptionResponses = {
16538
+ /**
16539
+ * Subscription created
16540
+ */
16541
+ 201: EmailSubscriptionResponse;
16542
+ };
16543
+
16544
+ export type CreateSubscriptionResponse = CreateSubscriptionResponses[keyof CreateSubscriptionResponses];
16545
+
16546
+ export type DeleteSubscriptionData = {
16547
+ body?: never;
16548
+ path: {
16549
+ /**
16550
+ * Repository key
16551
+ */
16552
+ key: string;
16553
+ /**
16554
+ * Subscription ID
16555
+ */
16556
+ subscription_id: string;
16557
+ };
16558
+ query?: never;
16559
+ url: '/api/v1/repositories/{key}/email-subscriptions/{subscription_id}';
16560
+ };
16561
+
16562
+ export type DeleteSubscriptionErrors = {
16563
+ /**
16564
+ * Not authenticated
16565
+ */
16566
+ 401: unknown;
16567
+ /**
16568
+ * Insufficient permissions
16569
+ */
16570
+ 403: unknown;
16571
+ /**
16572
+ * Subscription or repository not found
16573
+ */
16574
+ 404: unknown;
16575
+ };
16576
+
16577
+ export type DeleteSubscriptionResponses = {
16578
+ /**
16579
+ * Subscription deleted
16580
+ */
16581
+ 204: void;
16582
+ };
16583
+
16584
+ export type DeleteSubscriptionResponse = DeleteSubscriptionResponses[keyof DeleteSubscriptionResponses];
16585
+
16586
+ export type ListImageBuildsData = {
16587
+ body?: never;
16588
+ path: {
16589
+ /**
16590
+ * Repository key
16591
+ */
16592
+ key: string;
16593
+ };
16594
+ query?: never;
16595
+ url: '/api/v1/repositories/{key}/image-builds';
16596
+ };
16597
+
16598
+ export type ListImageBuildsResponses = {
16599
+ /**
16600
+ * Builds, newest first
16601
+ */
16602
+ 200: ImageBuildListResponse;
16603
+ };
16604
+
16605
+ export type ListImageBuildsResponse = ListImageBuildsResponses[keyof ListImageBuildsResponses];
16606
+
16607
+ export type CreateImageBuildData = {
16608
+ body: CreateImageBuildRequest;
16609
+ path: {
16610
+ /**
16611
+ * Repository key
16612
+ */
16613
+ key: string;
16614
+ };
16615
+ query?: never;
16616
+ url: '/api/v1/repositories/{key}/image-builds';
16617
+ };
16618
+
16619
+ export type CreateImageBuildErrors = {
16620
+ /**
16621
+ * Invalid spec, image name or tag; or the repository cannot receive builds
16622
+ */
16623
+ 400: unknown;
16624
+ /**
16625
+ * Image builds are not configured on this instance
16626
+ */
16627
+ 503: unknown;
16628
+ };
16629
+
16630
+ export type CreateImageBuildResponses = {
16631
+ /**
16632
+ * Build queued
16633
+ */
16634
+ 202: ImageBuildResponse;
16635
+ };
16636
+
16637
+ export type CreateImageBuildResponse = CreateImageBuildResponses[keyof CreateImageBuildResponses];
16638
+
16639
+ export type ImageBuildBaseInfoData = {
16640
+ body?: never;
16641
+ path: {
16642
+ /**
16643
+ * Repository key (the one being built into)
16644
+ */
16645
+ key: string;
16646
+ };
16647
+ query: {
16648
+ /**
16649
+ * Base image reference as the spec names it
16650
+ */
16651
+ image: string;
16652
+ };
16653
+ url: '/api/v1/repositories/{key}/image-builds/base-info';
16654
+ };
16655
+
16656
+ export type ImageBuildBaseInfoResponses = {
16657
+ 200: BaseImageInfo;
16658
+ };
16659
+
16660
+ export type ImageBuildBaseInfoResponse = ImageBuildBaseInfoResponses[keyof ImageBuildBaseInfoResponses];
16661
+
16662
+ export type RenderImageBuildData = {
16663
+ body: RenderImageBuildRequest;
16664
+ path: {
16665
+ /**
16666
+ * Repository key
16667
+ */
16668
+ key: string;
16669
+ };
16670
+ query?: never;
16671
+ url: '/api/v1/repositories/{key}/image-builds/render';
16672
+ };
16673
+
16674
+ export type RenderImageBuildErrors = {
16675
+ /**
16676
+ * The spec is invalid or refused by policy
16677
+ */
16678
+ 400: unknown;
16679
+ };
16680
+
16681
+ export type RenderImageBuildResponses = {
16682
+ /**
16683
+ * The Containerfile the server would build
16684
+ */
16685
+ 200: RenderImageBuildResponse;
16686
+ };
16687
+
16688
+ export type RenderImageBuildResponse2 = RenderImageBuildResponses[keyof RenderImageBuildResponses];
16689
+
16690
+ export type ImageBuildSettingsData = {
16691
+ body?: never;
16692
+ path: {
16693
+ /**
16694
+ * Repository key
16695
+ */
16696
+ key: string;
16697
+ };
16698
+ query?: never;
16699
+ url: '/api/v1/repositories/{key}/image-builds/settings';
16700
+ };
16701
+
16702
+ export type ImageBuildSettingsResponses = {
16703
+ /**
16704
+ * Builder availability and policy
16705
+ */
16706
+ 200: ImageBuildSettingsResponse;
16707
+ };
16708
+
16709
+ export type ImageBuildSettingsResponse2 = ImageBuildSettingsResponses[keyof ImageBuildSettingsResponses];
16710
+
16711
+ export type GetImageBuildData = {
16712
+ body?: never;
16713
+ path: {
16714
+ /**
16715
+ * Repository key
16716
+ */
16717
+ key: string;
16718
+ /**
16719
+ * Build id
16720
+ */
16721
+ id: string;
16722
+ };
16723
+ query?: never;
16724
+ url: '/api/v1/repositories/{key}/image-builds/{id}';
14814
16725
  };
14815
16726
 
14816
- export type ListSubscriptionsErrors = {
14817
- /**
14818
- * Not authenticated
14819
- */
14820
- 401: unknown;
14821
- /**
14822
- * Insufficient permissions
14823
- */
14824
- 403: unknown;
16727
+ export type GetImageBuildErrors = {
14825
16728
  /**
14826
- * Repository not found
16729
+ * No such build
14827
16730
  */
14828
16731
  404: unknown;
14829
16732
  };
14830
16733
 
14831
- export type ListSubscriptionsResponses = {
16734
+ export type GetImageBuildResponses = {
14832
16735
  /**
14833
- * List of email subscriptions
16736
+ * The build
14834
16737
  */
14835
- 200: EmailSubscriptionListResponse;
16738
+ 200: ImageBuildResponse;
14836
16739
  };
14837
16740
 
14838
- export type ListSubscriptionsResponse = ListSubscriptionsResponses[keyof ListSubscriptionsResponses];
16741
+ export type GetImageBuildResponse = GetImageBuildResponses[keyof GetImageBuildResponses];
14839
16742
 
14840
- export type CreateSubscriptionData = {
14841
- body: CreateEmailSubscriptionRequest;
16743
+ export type GetImageBuildLogData = {
16744
+ body?: never;
14842
16745
  path: {
14843
16746
  /**
14844
16747
  * Repository key
14845
16748
  */
14846
16749
  key: string;
16750
+ /**
16751
+ * Build id
16752
+ */
16753
+ id: string;
14847
16754
  };
14848
16755
  query?: never;
14849
- url: '/api/v1/repositories/{key}/email-subscriptions';
16756
+ url: '/api/v1/repositories/{key}/image-builds/{id}/log';
14850
16757
  };
14851
16758
 
14852
- export type CreateSubscriptionErrors = {
14853
- /**
14854
- * Validation error
14855
- */
14856
- 400: unknown;
14857
- /**
14858
- * Not authenticated
14859
- */
14860
- 401: unknown;
14861
- /**
14862
- * Insufficient permissions
14863
- */
14864
- 403: unknown;
16759
+ export type GetImageBuildLogErrors = {
14865
16760
  /**
14866
- * Repository not found
16761
+ * No such build
14867
16762
  */
14868
16763
  404: unknown;
14869
16764
  };
14870
16765
 
14871
- export type CreateSubscriptionResponses = {
16766
+ export type GetImageBuildLogResponses = {
14872
16767
  /**
14873
- * Subscription created
16768
+ * The buildctl output so far, text/plain
14874
16769
  */
14875
- 201: EmailSubscriptionResponse;
16770
+ 200: unknown;
14876
16771
  };
14877
16772
 
14878
- export type CreateSubscriptionResponse = CreateSubscriptionResponses[keyof CreateSubscriptionResponses];
14879
-
14880
- export type DeleteSubscriptionData = {
16773
+ export type InspectImageData = {
14881
16774
  body?: never;
14882
16775
  path: {
14883
16776
  /**
14884
16777
  * Repository key
14885
16778
  */
14886
16779
  key: string;
16780
+ };
16781
+ query: {
14887
16782
  /**
14888
- * Subscription ID
16783
+ * Image path within the repository
14889
16784
  */
14890
- subscription_id: string;
16785
+ image: string;
16786
+ /**
16787
+ * Tag or sha256: digest
16788
+ */
16789
+ reference: string;
14891
16790
  };
14892
- query?: never;
14893
- url: '/api/v1/repositories/{key}/email-subscriptions/{subscription_id}';
16791
+ url: '/api/v1/repositories/{key}/image-inspect';
14894
16792
  };
14895
16793
 
14896
- export type DeleteSubscriptionErrors = {
14897
- /**
14898
- * Not authenticated
14899
- */
14900
- 401: unknown;
14901
- /**
14902
- * Insufficient permissions
14903
- */
14904
- 403: unknown;
16794
+ export type InspectImageErrors = {
14905
16795
  /**
14906
- * Subscription or repository not found
16796
+ * Repository, image or reference not found
14907
16797
  */
14908
16798
  404: unknown;
14909
16799
  };
14910
16800
 
14911
- export type DeleteSubscriptionResponses = {
16801
+ export type InspectImageResponses = {
14912
16802
  /**
14913
- * Subscription deleted
16803
+ * The image as its manifest, config and provenance describe it
14914
16804
  */
14915
- 204: void;
16805
+ 200: ImageInspect;
14916
16806
  };
14917
16807
 
14918
- export type DeleteSubscriptionResponse = DeleteSubscriptionResponses[keyof DeleteSubscriptionResponses];
16808
+ export type InspectImageResponse = InspectImageResponses[keyof InspectImageResponses];
14919
16809
 
14920
16810
  export type ListRepoLabelsData = {
14921
16811
  body?: never;
@@ -15513,6 +17403,95 @@ export type UpdateRepoSecurityResponses = {
15513
17403
 
15514
17404
  export type UpdateRepoSecurityResponse = UpdateRepoSecurityResponses[keyof UpdateRepoSecurityResponses];
15515
17405
 
17406
+ export type GetRepoProxyScansData = {
17407
+ body?: never;
17408
+ path: {
17409
+ /**
17410
+ * Repository key
17411
+ */
17412
+ key: string;
17413
+ };
17414
+ query?: {
17415
+ /**
17416
+ * Cache path of a single entry, e.g.
17417
+ * `simple/click/click-8.0.0-py3-none-any.whl`. When set, the response
17418
+ * carries just that entry and omits the repository summary.
17419
+ */
17420
+ path?: string | null;
17421
+ page?: number | null;
17422
+ per_page?: number | null;
17423
+ };
17424
+ url: '/api/v1/repositories/{key}/security/proxy-scans';
17425
+ };
17426
+
17427
+ export type GetRepoProxyScansErrors = {
17428
+ /**
17429
+ * Authentication required
17430
+ */
17431
+ 401: ErrorResponse;
17432
+ /**
17433
+ * Repository or path not found
17434
+ */
17435
+ 404: ErrorResponse;
17436
+ };
17437
+
17438
+ export type GetRepoProxyScansError = GetRepoProxyScansErrors[keyof GetRepoProxyScansErrors];
17439
+
17440
+ export type GetRepoProxyScansResponses = {
17441
+ /**
17442
+ * Proxy scan verdicts for a repository
17443
+ */
17444
+ 200: ProxyScansResponse;
17445
+ };
17446
+
17447
+ export type GetRepoProxyScansResponse = GetRepoProxyScansResponses[keyof GetRepoProxyScansResponses];
17448
+
17449
+ export type RescanProxyCachedPathData = {
17450
+ body: ProxyRescanRequest;
17451
+ path: {
17452
+ /**
17453
+ * Repository key
17454
+ */
17455
+ key: string;
17456
+ };
17457
+ query?: never;
17458
+ url: '/api/v1/repositories/{key}/security/proxy-scans/rescan';
17459
+ };
17460
+
17461
+ export type RescanProxyCachedPathErrors = {
17462
+ /**
17463
+ * Authentication required
17464
+ */
17465
+ 401: ErrorResponse;
17466
+ /**
17467
+ * Repository or path not found
17468
+ */
17469
+ 404: ErrorResponse;
17470
+ /**
17471
+ * Cached object is above the inline scan cap
17472
+ */
17473
+ 422: ErrorResponse;
17474
+ /**
17475
+ * Rescan cooldown in effect: `RESCAN_THROTTLED`, with `Retry-After` naming the remaining cooldown in whole seconds.
17476
+ */
17477
+ 429: ErrorResponse;
17478
+ /**
17479
+ * Rescan could not produce a verdict: `NO_SCANNER_CONFIGURED` (no scanner is configured for this instance), `RESCAN_SCAN_FAILED` (the scan ran and errored), or `RESCAN_BUDGET_EXCEEDED` (the scan did not finish inside its budget). `Retry-After` is set only when cooldown time actually remains. The stored verdict is unchanged in every case.
17480
+ */
17481
+ 503: ErrorResponse;
17482
+ };
17483
+
17484
+ export type RescanProxyCachedPathError = RescanProxyCachedPathErrors[keyof RescanProxyCachedPathErrors];
17485
+
17486
+ export type RescanProxyCachedPathResponses = {
17487
+ /**
17488
+ * Rescan completed
17489
+ */
17490
+ 200: ProxyRescanResponse;
17491
+ };
17492
+
17493
+ export type RescanProxyCachedPathResponse = RescanProxyCachedPathResponses[keyof RescanProxyCachedPathResponses];
17494
+
15516
17495
  export type ListRepoScansData = {
15517
17496
  body?: never;
15518
17497
  path: {
@@ -15525,6 +17504,16 @@ export type ListRepoScansData = {
15525
17504
  repository_id?: string | null;
15526
17505
  artifact_id?: string | null;
15527
17506
  status?: string | null;
17507
+ /**
17508
+ * Restrict the listing to one scan engine (#3410), e.g. `grype`.
17509
+ *
17510
+ * `ScanResponse.scan_type` is already on the wire but could not be
17511
+ * filtered on, so a deployment running several engines had to page the
17512
+ * whole list and filter client-side. Validated against
17513
+ * [`KNOWN_SCAN_TYPES`]: an unrecognized value is a `400`, never an
17514
+ * unfiltered listing.
17515
+ */
17516
+ scan_type?: string | null;
15528
17517
  page?: number | null;
15529
17518
  per_page?: number | null;
15530
17519
  };
@@ -16637,6 +18626,39 @@ export type GetDashboardResponses = {
16637
18626
 
16638
18627
  export type GetDashboardResponse = GetDashboardResponses[keyof GetDashboardResponses];
16639
18628
 
18629
+ export type IngestExternalFindingsData = {
18630
+ body: IngestExternalFindingsRequest;
18631
+ path?: never;
18632
+ query?: never;
18633
+ url: '/api/v1/security/findings/external';
18634
+ };
18635
+
18636
+ export type IngestExternalFindingsErrors = {
18637
+ /**
18638
+ * Malformed submission
18639
+ */
18640
+ 400: ErrorResponse;
18641
+ /**
18642
+ * Admin privileges or the write:findings scope required
18643
+ */
18644
+ 403: ErrorResponse;
18645
+ /**
18646
+ * Artifact not found
18647
+ */
18648
+ 404: ErrorResponse;
18649
+ };
18650
+
18651
+ export type IngestExternalFindingsError = IngestExternalFindingsErrors[keyof IngestExternalFindingsErrors];
18652
+
18653
+ export type IngestExternalFindingsResponses = {
18654
+ /**
18655
+ * Findings ingested
18656
+ */
18657
+ 200: IngestExternalFindingsResponse;
18658
+ };
18659
+
18660
+ export type IngestExternalFindingsResponse2 = IngestExternalFindingsResponses[keyof IngestExternalFindingsResponses];
18661
+
16640
18662
  export type RevokeAcknowledgmentData = {
16641
18663
  body?: never;
16642
18664
  path: {
@@ -16886,6 +18908,16 @@ export type ListScansData = {
16886
18908
  repository_id?: string | null;
16887
18909
  artifact_id?: string | null;
16888
18910
  status?: string | null;
18911
+ /**
18912
+ * Restrict the listing to one scan engine (#3410), e.g. `grype`.
18913
+ *
18914
+ * `ScanResponse.scan_type` is already on the wire but could not be
18915
+ * filtered on, so a deployment running several engines had to page the
18916
+ * whole list and filter client-side. Validated against
18917
+ * [`KNOWN_SCAN_TYPES`]: an unrecognized value is a `400`, never an
18918
+ * unfiltered listing.
18919
+ */
18920
+ scan_type?: string | null;
16889
18921
  page?: number | null;
16890
18922
  per_page?: number | null;
16891
18923
  };
@@ -16940,6 +18972,27 @@ export type ListFindingsData = {
16940
18972
  id: string;
16941
18973
  };
16942
18974
  query?: {
18975
+ /**
18976
+ * Restrict the listing to one severity (#3410).
18977
+ *
18978
+ * Validated against [`KNOWN_SEVERITIES`]; an unrecognized token is a
18979
+ * `400` rather than an unfiltered page.
18980
+ */
18981
+ severity?: string | null;
18982
+ /**
18983
+ * Restrict the listing to findings written by one scanner (#3410).
18984
+ *
18985
+ * Matched exactly against `scan_findings.source`, which is already
18986
+ * returned as `FindingResponse.source`. Free text (no closed vocabulary):
18987
+ * bounded in length, not enumerated.
18988
+ */
18989
+ source?: string | null;
18990
+ /**
18991
+ * Restrict the listing to one vulnerability identifier (#3410).
18992
+ *
18993
+ * Matched exactly against `scan_findings.cve_id`.
18994
+ */
18995
+ cve_id?: string | null;
16943
18996
  page?: number | null;
16944
18997
  per_page?: number | null;
16945
18998
  };
@@ -18143,6 +20196,18 @@ export type ListUsersData = {
18143
20196
  search?: string | null;
18144
20197
  is_active?: boolean | null;
18145
20198
  is_admin?: boolean | null;
20199
+ /**
20200
+ * Filter on the service-account discriminator (#3634).
20201
+ *
20202
+ * Service accounts are rows in `users`, so an unfiltered listing mixes
20203
+ * them in with people. A client building a principal picker for
20204
+ * `POST /api/v1/permissions` must be able to exclude them: that endpoint's
20205
+ * `validate_principal` requires `principal_type = "service_account"` for
20206
+ * such a row and rejects it as `"user"`, so offering one under `user` is a
20207
+ * guaranteed 400. `None` keeps the historical unfiltered behavior, which
20208
+ * the audit actor filter and the group member picker both want.
20209
+ */
20210
+ is_service_account?: boolean | null;
18146
20211
  page?: number | null;
18147
20212
  per_page?: number | null;
18148
20213
  };
@@ -18505,7 +20570,7 @@ export type GetUserRolesData = {
18505
20570
 
18506
20571
  export type GetUserRolesResponses = {
18507
20572
  /**
18508
- * List of user roles
20573
+ * List of user roles. The `permissions` array describes the ROLE's capabilities, not this user's effective repository access: roles listed here are identity/SSO-mapping metadata and grant no repository access on their own (#3387 / #3522).
18509
20574
  */
18510
20575
  200: RoleListResponse;
18511
20576
  };
@@ -18526,7 +20591,7 @@ export type AssignRoleData = {
18526
20591
 
18527
20592
  export type AssignRoleResponses = {
18528
20593
  /**
18529
- * Role assigned successfully
20594
+ * Role assigned successfully. NOTE: roles assigned here are identity/SSO-mapping metadata and do NOT by themselves grant access to any repository — use POST /api/v1/permissions for that (#3387 / #3522).
18530
20595
  */
18531
20596
  200: unknown;
18532
20597
  };
@@ -18977,6 +21042,121 @@ export type LivenessCheckResponses = {
18977
21042
 
18978
21043
  export type LivenessCheckResponse = LivenessCheckResponses[keyof LivenessCheckResponses];
18979
21044
 
21045
+ export type XmlrpcData = {
21046
+ /**
21047
+ * XML-RPC `methodCall` (opaque). Supported methods: `browse([classifier, ...])` and `list_packages()`.
21048
+ */
21049
+ body: string;
21050
+ path: {
21051
+ /**
21052
+ * Repository key
21053
+ */
21054
+ repo_key: string;
21055
+ };
21056
+ query?: never;
21057
+ url: '/pypi/{repo_key}/pypi';
21058
+ };
21059
+
21060
+ export type XmlrpcErrors = {
21061
+ /**
21062
+ * Repository not found
21063
+ */
21064
+ 404: unknown;
21065
+ /**
21066
+ * Request body larger than 64 KiB
21067
+ */
21068
+ 413: unknown;
21069
+ };
21070
+
21071
+ export type XmlrpcResponses = {
21072
+ /**
21073
+ * XML-RPC `methodResponse` (opaque). `browse` answers `[[name, version], ...]` from stored metadata (hosted repositories, and the hosted members of a virtual); an unknown method, a malformed request, or either method on a remote repository or a virtual without hosted members (fault -32001: the call is never forwarded upstream; JupyterLab surfaces it as a generic error, the reason is in the response) answers an XML-RPC fault, not an HTTP error.
21074
+ */
21075
+ 200: string;
21076
+ };
21077
+
21078
+ export type XmlrpcResponse = XmlrpcResponses[keyof XmlrpcResponses];
21079
+
21080
+ export type LegacyProjectJsonData = {
21081
+ body?: never;
21082
+ path: {
21083
+ /**
21084
+ * Repository key
21085
+ */
21086
+ repo_key: string;
21087
+ /**
21088
+ * Project name; normalized per PEP 503 for the lookup
21089
+ */
21090
+ project: string;
21091
+ };
21092
+ query?: never;
21093
+ url: '/pypi/{repo_key}/pypi/{project}/json';
21094
+ };
21095
+
21096
+ export type LegacyProjectJsonErrors = {
21097
+ /**
21098
+ * Project blocked by a curation rule
21099
+ */
21100
+ 403: unknown;
21101
+ /**
21102
+ * Repository or project not found
21103
+ */
21104
+ 404: unknown;
21105
+ };
21106
+
21107
+ export type LegacyProjectJsonResponses = {
21108
+ /**
21109
+ * Legacy PyPI JSON document: `info` for the latest release, `releases` keyed by version, `urls` for the latest release. Download URLs point at this repository.
21110
+ */
21111
+ 200: {
21112
+ [key: string]: unknown;
21113
+ };
21114
+ };
21115
+
21116
+ export type LegacyProjectJsonResponse = LegacyProjectJsonResponses[keyof LegacyProjectJsonResponses];
21117
+
21118
+ export type LegacyReleaseJsonData = {
21119
+ body?: never;
21120
+ path: {
21121
+ /**
21122
+ * Repository key
21123
+ */
21124
+ repo_key: string;
21125
+ /**
21126
+ * Project name; normalized per PEP 503 for the lookup
21127
+ */
21128
+ project: string;
21129
+ /**
21130
+ * Release version (PEP 440; `1.0` matches a stored `1.0.0`)
21131
+ */
21132
+ version: string;
21133
+ };
21134
+ query?: never;
21135
+ url: '/pypi/{repo_key}/pypi/{project}/{version}/json';
21136
+ };
21137
+
21138
+ export type LegacyReleaseJsonErrors = {
21139
+ /**
21140
+ * Project or version blocked by a curation rule
21141
+ */
21142
+ 403: unknown;
21143
+ /**
21144
+ * Repository, project or release not found
21145
+ */
21146
+ 404: unknown;
21147
+ };
21148
+
21149
+ export type LegacyReleaseJsonResponses = {
21150
+ /**
21151
+ * Legacy PyPI JSON document for one release: `info` and `urls`. Download URLs point at this repository.
21152
+ */
21153
+ 200: {
21154
+ [key: string]: unknown;
21155
+ };
21156
+ };
21157
+
21158
+ export type LegacyReleaseJsonResponse = LegacyReleaseJsonResponses[keyof LegacyReleaseJsonResponses];
21159
+
18980
21160
  export type ReadinessCheckData = {
18981
21161
  body?: never;
18982
21162
  path?: never;