diff --git a/AGENTS.md b/AGENTS.md index b0b6d8a2..148a62f6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -58,9 +58,9 @@ after its format id, linked into the server like `crates/formats/nuget` under `crates/` (no `crates/format-`) or as a module of the server: it implements `FormatPlugin` with the layout [crates/formats/README.md](crates/formats/README.md) describes. Docker / OCI -(`crates/format-oci`) is not there yet and is to move to -`crates/formats/docker`, in a pull request of its own; until then it is not -the model for a new format. +is in `crates/formats/docker` but still native: the server's registry serves +it under `/v2`, not through `FormatPlugin`. Until it implements +`FormatPlugin`, it is not the model for a new format. ## Changelog: a fragment per change, never CHANGELOG.md diff --git a/Cargo.lock b/Cargo.lock index c5b19460..562fab73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1734,6 +1734,38 @@ dependencies = [ "zip", ] +[[package]] +name = "forge-format-docker" +version = "1.1.0" +dependencies = [ + "async-trait", + "axum", + "base64 0.23.1", + "bytes", + "chrono", + "flate2", + "forge-cache", + "forge-core", + "forge-crypto", + "forge-db", + "forge-storage", + "futures-util", + "hex", + "jsonwebtoken", + "rand 0.10.3", + "reqwest", + "serde", + "serde_json", + "sha2 0.11.1", + "sqlx", + "thiserror", + "tokio", + "tokio-util", + "tracing", + "url", + "uuid", +] + [[package]] name = "forge-format-npm" version = "1.0.0" @@ -1777,38 +1809,6 @@ dependencies = [ "url", ] -[[package]] -name = "forge-oci" -version = "1.1.0" -dependencies = [ - "async-trait", - "axum", - "base64 0.23.1", - "bytes", - "chrono", - "flate2", - "forge-cache", - "forge-core", - "forge-crypto", - "forge-db", - "forge-storage", - "futures-util", - "hex", - "jsonwebtoken", - "rand 0.10.3", - "reqwest", - "serde", - "serde_json", - "sha2 0.11.1", - "sqlx", - "thiserror", - "tokio", - "tokio-util", - "tracing", - "url", - "uuid", -] - [[package]] name = "forge-plugin" version = "1.1.0" @@ -1841,10 +1841,10 @@ dependencies = [ "forge-core", "forge-crypto", "forge-db", + "forge-format-docker", "forge-format-npm", "forge-format-nuget", "forge-format-raw", - "forge-oci", "forge-plugin", "forge-storage", "futures-util", diff --git a/Cargo.toml b/Cargo.toml index 598703d2..50864dd6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,9 +8,9 @@ members = [ "crates/crypto", "crates/plugin-api", "crates/plugin", - "crates/format-oci", "crates/server", "crates/e2e", + "crates/formats/docker", "crates/formats/nuget", "crates/formats/npm", "crates/formats/raw", diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index c3129f44..cbf54fd5 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -254,10 +254,10 @@ Every package format is a format plugin, a crate in [`crates/formats/`](./crates/formats) linked into the server (see [docs/format-plugins.md](./docs/format-plugins.md)): NuGet, npm and raw. A new format goes in `crates/formats/` too, never in a `crates/format-` -crate or the server. Docker / OCI (`crates/format-oci`) is not there yet and -is to move to `crates/formats/docker`. A repository of a plugin format is -created with `"format": ""` (hosted, proxy or group; a plugin format has -proxies when it implements the upstream side) and served under +crate or the server. Docker / OCI is in `crates/formats/docker` but still +native, served by the server's registry under `/v2`. A repository of a plugin +format is created with `"format": ""` (hosted, proxy or group; a plugin +format has proxies when it implements the upstream side) and served under `/repository//` unless the plugin names another mount (NuGet's is `/v3`, npm's `/npm`). Helm charts are pushed to docker repositories, see [docs/docker.md](docs/docker.md#helm-charts). diff --git a/README.md b/README.md index 43aa0dc8..92fcb31e 100644 --- a/README.md +++ b/README.md @@ -55,10 +55,10 @@ A Cargo workspace of small crates plus the web SPA: | `storage` | `forge-storage` | CAS over S3, blob outbox / GC reconciler. | | `cache` | `forge-cache` | In-process L1 + optional Redis L2 with cross-instance invalidation (no Postgres advisory locks). | | `core` | `forge-core` | Domain logic: repo dispatch, auth chain, authz/RBAC, sessions, OIDC, retention. | -| `format-oci` | `forge-oci` | Docker / OCI registry: the distribution-spec `/v2` API, manifests, registry tokens, hosted/proxy/group resolution. | | `plugin-api` | `forge-plugin-api` | The format-plugin contract: the `FormatPlugin` trait and its types. | | `plugin` | `forge-plugin` | The host side of format plugins: an installed plugin and its adapter to the repository machinery. | | `formats/` | `forge-format-*` | Format plugins, built into the server: `nuget`, `npm`, `raw`. | +| `formats/docker` | `forge-format-docker` | Docker / OCI registry, still native: the distribution-spec `/v2` API, manifests, registry tokens, hosted/proxy/group resolution. | | `server` | `forge-server` | Axum HTTP server: the format plugins' feeds (NuGet at `/v3`, npm at `/npm`, raw files at `/raw`), the file store of files formats, the Docker registry, `/admin` + `/auth` REST, background workers, static SPA serving. | | `e2e` | `forge-e2e` | End-to-end suite (testcontainers + mock upstream/IdP). | | `xtask` | — | The task runner (`cargo xtask …`); replaces Make/Just. | @@ -66,8 +66,8 @@ A Cargo workspace of small crates plus the web SPA: **Every format is a plugin in `crates/formats/`.** A package format is a crate in `crates/formats//` implementing `FormatPlugin`, linked into the -server. Docker / OCI (`crates/format-oci`) is not there yet and is to move to -`crates/formats/docker`. +server. Docker / OCI is in `crates/formats/docker` but still native: the +server's registry serves it under `/v2`, not through `FormatPlugin`. **Single-origin serving.** `forge-server` mounts each format plugin's feed (NuGet at `/v3`, npm at `/npm`, others at `/repository`), the Docker / OCI registry (`/v2`), diff --git a/crates/formats/README.md b/crates/formats/README.md index 50f179ef..09104ab1 100644 --- a/crates/formats/README.md +++ b/crates/formats/README.md @@ -11,6 +11,10 @@ the design, the contract and how to write one. | [`npm`](npm) | `npm` | npm registries at `/npm` for npm, pnpm, Yarn and Bun: publish, install, dist-tags, deprecations, unpublishing, search, audits and logins; hosted, proxy and group repositories ([docs/npm.md](../../docs/npm.md)) | | [`raw`](raw) | `raw` | Raw files at `/raw`: files under paths, uploads with `PUT` or a form, ranges, checksum sidecars, listings; hosted, proxy and group repositories ([docs/raw.md](../../docs/raw.md)) | +[`docker`](docker) holds Docker / OCI (`forge-format-docker`), which is still +native: the server's registry serves it under `/v2`, not through +`FormatPlugin` ([docs/docker.md](../../docs/docker.md)). + A plugin directory holds: - `Cargo.toml`: a member of the workspace; its `version` is the plugin's; diff --git a/crates/format-oci/Cargo.toml b/crates/formats/docker/Cargo.toml similarity index 83% rename from crates/format-oci/Cargo.toml rename to crates/formats/docker/Cargo.toml index 3c089539..16970a83 100644 --- a/crates/format-oci/Cargo.toml +++ b/crates/formats/docker/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "forge-oci" +name = "forge-format-docker" version.workspace = true edition.workspace = true rust-version.workspace = true @@ -7,11 +7,11 @@ license.workspace = true publish.workspace = true [dependencies] -forge-core = { path = "../core" } -forge-db = { path = "../db" } -forge-storage = { path = "../storage" } -forge-cache = { path = "../cache" } -forge-crypto = { path = "../crypto" } +forge-core = { path = "../../core" } +forge-db = { path = "../../db" } +forge-storage = { path = "../../storage" } +forge-cache = { path = "../../cache" } +forge-crypto = { path = "../../crypto" } axum = { workspace = true } tokio = { workspace = true, features = ["rt", "sync"] } diff --git a/crates/format-oci/src/auth.rs b/crates/formats/docker/src/auth.rs similarity index 100% rename from crates/format-oci/src/auth.rs rename to crates/formats/docker/src/auth.rs diff --git a/crates/format-oci/src/chart.rs b/crates/formats/docker/src/chart.rs similarity index 100% rename from crates/format-oci/src/chart.rs rename to crates/formats/docker/src/chart.rs diff --git a/crates/format-oci/src/digest.rs b/crates/formats/docker/src/digest.rs similarity index 100% rename from crates/format-oci/src/digest.rs rename to crates/formats/docker/src/digest.rs diff --git a/crates/format-oci/src/error.rs b/crates/formats/docker/src/error.rs similarity index 100% rename from crates/format-oci/src/error.rs rename to crates/formats/docker/src/error.rs diff --git a/crates/format-oci/src/gc.rs b/crates/formats/docker/src/gc.rs similarity index 100% rename from crates/format-oci/src/gc.rs rename to crates/formats/docker/src/gc.rs diff --git a/crates/format-oci/src/group.rs b/crates/formats/docker/src/group.rs similarity index 100% rename from crates/format-oci/src/group.rs rename to crates/formats/docker/src/group.rs diff --git a/crates/format-oci/src/import.rs b/crates/formats/docker/src/import.rs similarity index 100% rename from crates/format-oci/src/import.rs rename to crates/formats/docker/src/import.rs diff --git a/crates/format-oci/src/lib.rs b/crates/formats/docker/src/lib.rs similarity index 100% rename from crates/format-oci/src/lib.rs rename to crates/formats/docker/src/lib.rs diff --git a/crates/format-oci/src/manifest.rs b/crates/formats/docker/src/manifest.rs similarity index 100% rename from crates/format-oci/src/manifest.rs rename to crates/formats/docker/src/manifest.rs diff --git a/crates/format-oci/src/path.rs b/crates/formats/docker/src/path.rs similarity index 100% rename from crates/format-oci/src/path.rs rename to crates/formats/docker/src/path.rs diff --git a/crates/format-oci/src/proxy.rs b/crates/formats/docker/src/proxy.rs similarity index 100% rename from crates/format-oci/src/proxy.rs rename to crates/formats/docker/src/proxy.rs diff --git a/crates/format-oci/src/pull.rs b/crates/formats/docker/src/pull.rs similarity index 100% rename from crates/format-oci/src/pull.rs rename to crates/formats/docker/src/pull.rs diff --git a/crates/format-oci/src/push.rs b/crates/formats/docker/src/push.rs similarity index 100% rename from crates/format-oci/src/push.rs rename to crates/formats/docker/src/push.rs diff --git a/crates/format-oci/src/reference.rs b/crates/formats/docker/src/reference.rs similarity index 100% rename from crates/format-oci/src/reference.rs rename to crates/formats/docker/src/reference.rs diff --git a/crates/format-oci/src/service.rs b/crates/formats/docker/src/service.rs similarity index 100% rename from crates/format-oci/src/service.rs rename to crates/formats/docker/src/service.rs diff --git a/crates/format-oci/src/token.rs b/crates/formats/docker/src/token.rs similarity index 100% rename from crates/format-oci/src/token.rs rename to crates/formats/docker/src/token.rs diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml index 65ea6417..62789037 100644 --- a/crates/server/Cargo.toml +++ b/crates/server/Cargo.toml @@ -21,7 +21,8 @@ forge-cache = { path = "../cache" } forge-core = { path = "../core" } forge-crypto = { path = "../crypto" } forge-plugin = { path = "../plugin" } -forge-oci = { path = "../format-oci" } +# Docker / OCI, still native: the registry under /v2 (crate::registry). +forge-format-docker = { path = "../formats/docker" } # The built-in format plugins (crates/formats/nuget, crates/formats/npm, # crates/formats/raw), linked in. forge-format-nuget = { path = "../formats/nuget" } diff --git a/crates/server/src/admin/proxy_cache.rs b/crates/server/src/admin/proxy_cache.rs index dd043152..4f004057 100644 --- a/crates/server/src/admin/proxy_cache.rs +++ b/crates/server/src/admin/proxy_cache.rs @@ -99,10 +99,10 @@ pub async fn invalidate( } } Some(p) if docker => { - if !forge_oci::reference::valid_name(&p) { + if !forge_format_docker::reference::valid_name(&p) { return bad_request("package is not a valid image name"); } - Some(forge_oci::proxied_image(&repo, &p)) + Some(forge_format_docker::proxied_image(&repo, &p)) } Some(p) => { let format = match state.formats.for_repository(&repo) { diff --git a/crates/server/src/admin/repositories.rs b/crates/server/src/admin/repositories.rs index ffca86d3..323d98aa 100644 --- a/crates/server/src/admin/repositories.rs +++ b/crates/server/src/admin/repositories.rs @@ -873,7 +873,7 @@ async fn docker_options( return writable_member_option(state, writable, kind, options.writable_member, config) .await; } - if !forge_oci::reference::valid_name_component(name) { + if !forge_format_docker::reference::valid_name_component(name) { return Err(bad_request(format!( "invalid docker repository name {name:?}: image names start with it, so use \ lowercase letters and digits, separated by '.', '_', '__' or '-'" diff --git a/crates/server/src/browse_images.rs b/crates/server/src/browse_images.rs index 90ff75a0..e3b484bb 100644 --- a/crates/server/src/browse_images.rs +++ b/crates/server/src/browse_images.rs @@ -25,8 +25,8 @@ use chrono::{DateTime, Utc}; use forge_core::auth::principal::Principal; use forge_db::model::{RepoKind, Repository}; use forge_db::{oci_dao, repository_dao}; -use forge_oci::chart; -use forge_oci::manifest::{self, ManifestKind, MAX_MANIFEST_BYTES}; +use forge_format_docker::chart; +use forge_format_docker::manifest::{self, ManifestKind, MAX_MANIFEST_BYTES}; use forge_storage::BlobRef; use serde::{Deserialize, Serialize}; @@ -119,7 +119,7 @@ pub struct ImageDetail { /// The registry host of the server (`host[:port]` of `public_base_url`). fn registry_host(state: &AppState) -> String { - forge_oci::registry_origin(&state.config.public_base_url()).1 + forge_format_docker::registry_origin(&state.config.public_base_url()).1 } /// Where `repo`'s images are pulled from: its own host, or @@ -266,7 +266,7 @@ pub async fn image_detail( Ok(repo) => repo, Err(resp) => return resp, }; - if !forge_oci::reference::valid_name(&image) { + if !forge_format_docker::reference::valid_name(&image) { return (StatusCode::NOT_FOUND, "image not found").into_response(); } let sources = match sources(&state, &principal, &repo).await { @@ -521,8 +521,8 @@ pub async fn chart_detail( }; let not_found = || (StatusCode::NOT_FOUND, "chart not found").into_response(); let image = query.image; - if !forge_oci::reference::valid_name(&image) - || forge_oci::digest::Digest::parse(&query.digest).is_err() + if !forge_format_docker::reference::valid_name(&image) + || forge_format_docker::digest::Digest::parse(&query.digest).is_err() { return not_found(); } diff --git a/crates/server/src/nexus_import/mod.rs b/crates/server/src/nexus_import/mod.rs index e447938b..b9ddec78 100644 --- a/crates/server/src/nexus_import/mod.rs +++ b/crates/server/src/nexus_import/mod.rs @@ -25,7 +25,7 @@ //! (`action = "import"`). A version Forge holds with the same SHA-256 //! is skipped without a download; //! * a Docker tag is copied through the Nexus repository's registry API -//! ([`forge_oci::Registry::import_tag`]): digests are kept, +//! ([`forge_format_docker::Registry::import_tag`]): digests are kept, //! multi-platform indexes arrive with every child manifest, and a //! referrer is copied once its subject is in Forge; //! * what Nexus recorded is kept: the publish time (`blobCreated`, for a @@ -63,7 +63,7 @@ use forge_crypto::PlaintextSecret; use forge_db::import_dao::{self, ImportItem, NewItem, NexusImport}; use forge_db::model::{Repository, DOCKER_FORMAT}; use forge_db::{repository_dao, secret_dao, user_dao}; -use forge_oci::import::{ImageImportOptions, ImageOutcome, ImportSource}; +use forge_format_docker::import::{ImageImportOptions, ImageOutcome, ImportSource}; use forge_storage::StagedBlob; use futures_util::{FutureExt, StreamExt, TryStreamExt}; use serde_json::Value as JsonValue; @@ -210,7 +210,7 @@ enum Target { /// Docker, through the registry, from the Nexus repository's registry /// API. Images { - registry: forge_oci::Registry, + registry: forge_format_docker::Registry, source: ImportSource, }, } @@ -705,7 +705,7 @@ impl Run<'_> { async fn copy_image( &self, ctx: &Ctx, - registry: &forge_oci::Registry, + registry: &forge_format_docker::Registry, from: &ImportSource, kind: &str, source: &SourceItem, diff --git a/crates/server/src/registry.rs b/crates/server/src/registry.rs index fc69a56e..31a8e59f 100644 --- a/crates/server/src/registry.rs +++ b/crates/server/src/registry.rs @@ -16,7 +16,7 @@ use forge_crypto::service::EnvelopeService; use forge_crypto::{ExposeSecret, PlaintextSecret}; use forge_db::model::Repository; use forge_db::{authz_dao, secret_dao, workload_api_key_dao}; -use forge_oci::token::TokenKeys; +use forge_format_docker::token::TokenKeys; use sha2::Digest; use sqlx::PgPool; @@ -36,7 +36,7 @@ pub async fn registry(State(state): State, req: Request) -> Resp /// Workload pushes go to the trusted-publishing ledger. pub(crate) struct LedgerRecorder; -impl forge_oci::PublishRecorder for LedgerRecorder { +impl forge_format_docker::PublishRecorder for LedgerRecorder { fn for_repository(&self, repository: &Repository) -> Arc { crate::dispatch::workload_ledger_policy(repository) } @@ -50,7 +50,7 @@ pub(crate) struct WorkloadLiveness { } #[async_trait::async_trait] -impl forge_oci::WorkloadCheck for WorkloadLiveness { +impl forge_format_docker::WorkloadCheck for WorkloadLiveness { async fn still_valid(&self, principal: &Principal) -> Result { let Principal::Workload { realm_id, @@ -91,7 +91,7 @@ pub(crate) fn amend_registry_rejection(public_base_url: &str, response: Response { return response; } - let (scheme, service) = forge_oci::registry_origin(public_base_url); + let (scheme, service) = forge_format_docker::registry_origin(public_base_url); let challenge = format!("Bearer realm=\"{scheme}://{service}/v2/token\",service=\"{service}\""); let body = serde_json::json!({ "errors": [{ "code": "UNAUTHORIZED", "message": "invalid credentials" }] diff --git a/crates/server/src/state.rs b/crates/server/src/state.rs index d2955eed..189257db 100644 --- a/crates/server/src/state.rs +++ b/crates/server/src/state.rs @@ -99,7 +99,7 @@ pub struct AppState { /// install's shared one ([`crate::registry::load_token_keys`] via /// [`AppState::with_registry_keys`]) so every instance accepts every /// instance's tokens. - pub registry_keys: forge_oci::token::TokenKeys, + pub registry_keys: forge_format_docker::token::TokenKeys, /// This process among the instances of an install, as per-instance /// reports (the local blob cache's statistics) name it. pub instance: Arc, @@ -371,7 +371,7 @@ impl AppState { oidc_login_starts, envelope: None, upstream, - registry_keys: forge_oci::token::TokenKeys::new(vec![{ + registry_keys: forge_format_docker::token::TokenKeys::new(vec![{ use rand::Rng; let mut key = vec![0u8; 32]; rand::rng().fill_bytes(&mut key); @@ -389,14 +389,14 @@ impl AppState { } /// Use `keys` to sign and verify registry tokens. - pub fn with_registry_keys(mut self, keys: forge_oci::token::TokenKeys) -> Self { + pub fn with_registry_keys(mut self, keys: forge_format_docker::token::TokenKeys) -> Self { self.registry_keys = keys; self } /// The Docker / OCI registry service, wired to this state. - pub fn registry(&self) -> forge_oci::Registry { - forge_oci::Registry::new(forge_oci::RegistryParts { + pub fn registry(&self) -> forge_format_docker::Registry { + forge_format_docker::Registry::new(forge_format_docker::RegistryParts { pool: self.pool.clone(), cas: self.cas.clone(), store: self.blob_store.clone(), @@ -404,7 +404,7 @@ impl AppState { authz: self.authz.clone(), http: self.upstream.clone(), envelope: self.envelope.clone(), - config: forge_oci::RegistryConfig { + config: forge_format_docker::RegistryConfig { public_base_url: self.config.public_base_url(), max_blob_bytes: self.config.docker_max_blob_bytes(), default_max_upload_bytes: self.config.default_upload_limit(DOCKER_FORMAT), diff --git a/crates/server/src/workers.rs b/crates/server/src/workers.rs index f3b3db96..e1b84140 100644 --- a/crates/server/src/workers.rs +++ b/crates/server/src/workers.rs @@ -324,7 +324,7 @@ fn spawn_registry_sweeper( ticker.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay); loop { ticker.tick().await; - match forge_oci::gc::sweep_once( + match forge_format_docker::gc::sweep_once( &pool, chrono::Duration::seconds(docker.upload_ttl_seconds as i64), chrono::Duration::seconds(docker.unreferenced_blob_ttl_seconds as i64), diff --git a/crates/server/tests/admin.rs b/crates/server/tests/admin.rs index 0b66360e..a91ca36c 100644 --- a/crates/server/tests/admin.rs +++ b/crates/server/tests/admin.rs @@ -1570,8 +1570,8 @@ async fn registry_token_key_survives_dek_rotation() { .unwrap(); assert_eq!(stored().await, after, "not replaced"); let now = chrono::Utc::now().timestamp(); - let claims = forge_oci::token::Claims { - iss: forge_oci::token::issuer("https://forge.example.com"), + let claims = forge_format_docker::token::Claims { + iss: forge_format_docker::token::issuer("https://forge.example.com"), aud: "forge.example.com".into(), sub: "anonymous".into(), iat: now, @@ -1579,11 +1579,11 @@ async fn registry_token_key_survives_dek_rotation() { exp: now + 300, jti: "j".into(), access: Vec::new(), - fp: forge_oci::token::TokenPrincipal::Anonymous, + fp: forge_format_docker::token::TokenPrincipal::Anonymous, }; - let token = forge_oci::token::issue(&srv.state.registry_keys, &claims).unwrap(); + let token = forge_format_docker::token::issue(&srv.state.registry_keys, &claims).unwrap(); assert!( - forge_oci::token::verify(&restarted, &token, &claims.iss, &claims.aud).is_some(), + forge_format_docker::token::verify(&restarted, &token, &claims.iss, &claims.aud).is_some(), "a restarted instance accepts the running instance's tokens" ); } diff --git a/crates/server/tests/registry.rs b/crates/server/tests/registry.rs index 3ab59a0b..7095e978 100644 --- a/crates/server/tests/registry.rs +++ b/crates/server/tests/registry.rs @@ -410,7 +410,7 @@ async fn version_check_challenges_and_tokens_authenticate() { async fn token_requests_name_a_bounded_number_of_repositories() { use base64::Engine; let srv = common::start().await; - let max = forge_oci::token::MAX_SCOPES; + let max = forge_format_docker::token::MAX_SCOPES; let request = |scopes: Vec| { let mut req = srv .client() @@ -1700,8 +1700,8 @@ impl MockRegistry { return resp; } let head = req.method() == Method::HEAD; - match forge_oci::path::parse(&path) { - Some(forge_oci::path::Endpoint::Manifest { name, reference }) => { + match forge_format_docker::path::parse(&path) { + Some(forge_format_docker::path::Endpoint::Manifest { name, reference }) => { let found = self .manifests .lock() @@ -1733,7 +1733,7 @@ impl MockRegistry { ) .into_response() } - Some(forge_oci::path::Endpoint::Blob { digest, .. }) => { + Some(forge_format_docker::path::Endpoint::Blob { digest, .. }) => { if head && self.lie_on_head.load(Ordering::SeqCst) { return StatusCode::OK.into_response(); } @@ -1759,7 +1759,7 @@ impl MockRegistry { } body.into_response() } - Some(forge_oci::path::Endpoint::TagsList { name }) => { + Some(forge_format_docker::path::Endpoint::TagsList { name }) => { let query = req.uri().query().unwrap_or_default().to_string(); self.tag_queries.lock().unwrap().push(query.clone()); let mut n: Option = None; @@ -2711,7 +2711,7 @@ async fn deleting_an_image_never_frees_a_layer_another_image_uses() { assert_eq!(ref_count(&srv, &layer).await, Some(2), "one link per image"); let sweep = || { - forge_oci::gc::sweep_once( + forge_format_docker::gc::sweep_once( &srv.pool, chrono::Duration::zero(), chrono::Duration::zero(), diff --git a/docs/format-plugins.md b/docs/format-plugins.md index 64ab1074..3ee3ad7c 100644 --- a/docs/format-plugins.md +++ b/docs/format-plugins.md @@ -543,7 +543,7 @@ with Bearer tokens, read layers with `Range` requests, and expect proxies of Docker Hub and other registries. Every one of those is on the roadmap above or outside the contract altogether. -So Docker is a native format (`crates/format-oci`, served under `/v2`), +So Docker is a native format (`crates/formats/docker`, served under `/v2`), registered next to the plugins: `GET /admin/formats` lists it with all three repository kinds, the admin API and the web UI create its repositories the same way, a group holds members of its format only, and repositories, RBAC,