max / makenotwork
- Co-Authored-By
- Claude Opus 5 (1M context) <noreply@anthropic.com>
- Claude-Session
- https://claude.ai/code/session_01J1yAFMokhGYCs3UT8UaCZr
20 files changed,
+522 insertions,
-294 deletions
| @@ -1837,6 +1837,8 @@ | |||
| 1837 | 1837 | [[package]] | |
| 1838 | 1838 | name = "makeover-layout" | |
| 1839 | 1839 | version = "0.44.0" | |
| 1840 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 1841 | + | checksum = "f4c5dd2718ddfe428033a2c55d810e3b567edf9273f148875c1aa0291735ae12" | |
| 1840 | 1842 | ||
| 1841 | 1843 | [[package]] | |
| 1842 | 1844 | name = "makeover-timing" | |
| @@ -1850,6 +1852,8 @@ | |||
| 1850 | 1852 | [[package]] | |
| 1851 | 1853 | name = "makeover-tui" | |
| 1852 | 1854 | version = "0.44.0" | |
| 1855 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 1856 | + | checksum = "a39ca8938ca1e082ce16ac772592bc81aa0a14c461c5ec0b60bf55b0728ae7e5" | |
| 1853 | 1857 | dependencies = [ | |
| 1854 | 1858 | "makeover", | |
| 1855 | 1859 | "makeover-layout", | |
| @@ -4773,6 +4777,62 @@ | |||
| 4773 | 4777 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 4774 | 4778 | checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" | |
| 4775 | 4779 | ||
| 4780 | + | [[patch.unused]] | |
| 4781 | + | name = "docengine" | |
| 4782 | + | version = "0.7.0" | |
| 4783 | + | ||
| 4784 | + | [[patch.unused]] | |
| 4785 | + | name = "quasi-axum" | |
| 4786 | + | version = "0.103.0" | |
| 4787 | + | ||
| 4788 | + | [[patch.unused]] | |
| 4789 | + | name = "quasi-basics" | |
| 4790 | + | version = "0.103.0" | |
| 4791 | + | ||
| 4792 | + | [[patch.unused]] | |
| 4793 | + | name = "quasi-declare" | |
| 4794 | + | version = "0.1.11" | |
| 4795 | + | ||
| 4796 | + | [[patch.unused]] | |
| 4797 | + | name = "quasi-http" | |
| 4798 | + | version = "0.103.0" | |
| 4799 | + | ||
| 4800 | + | [[patch.unused]] | |
| 4801 | + | name = "quasi-immediate" | |
| 4802 | + | version = "0.103.0" | |
| 4803 | + | ||
| 4804 | + | [[patch.unused]] | |
| 4805 | + | name = "quasi-notifs" | |
| 4806 | + | version = "0.103.0" | |
| 4807 | + | ||
| 4808 | + | [[patch.unused]] | |
| 4809 | + | name = "quasi-router" | |
| 4810 | + | version = "0.103.0" | |
| 4811 | + | ||
| 4812 | + | [[patch.unused]] | |
| 4813 | + | name = "quasi-store" | |
| 4814 | + | version = "0.1.0" | |
| 4815 | + | ||
| 4816 | + | [[patch.unused]] | |
| 4817 | + | name = "quasi-tauri" | |
| 4818 | + | version = "0.103.0" | |
| 4819 | + | ||
| 4820 | + | [[patch.unused]] | |
| 4821 | + | name = "quasi-webview" | |
| 4822 | + | version = "0.103.0" | |
| 4823 | + | ||
| 4824 | + | [[patch.unused]] | |
| 4825 | + | name = "makeover-build" | |
| 4826 | + | version = "0.67.0" | |
| 4827 | + | ||
| 4828 | + | [[patch.unused]] | |
| 4829 | + | name = "makeover-webview" | |
| 4830 | + | version = "0.74.0" | |
| 4831 | + | ||
| 4832 | + | [[patch.unused]] | |
| 4833 | + | name = "quasi-type" | |
| 4834 | + | version = "0.1.3" | |
| 4835 | + | ||
| 4776 | 4836 | [[patch.unused]] | |
| 4777 | 4837 | name = "kberg" | |
| 4778 | 4838 | version = "0.1.0" | |
| @@ -4789,66 +4849,6 @@ | |||
| 4789 | 4849 | name = "tagtree" | |
| 4790 | 4850 | version = "0.4.1" | |
| 4791 | 4851 | ||
| 4792 | - | [[patch.unused]] | |
| 4793 | - | name = "quasi-axum" | |
| 4794 | - | version = "0.99.0" | |
| 4795 | - | ||
| 4796 | - | [[patch.unused]] | |
| 4797 | - | name = "quasi-basics" | |
| 4798 | - | version = "0.99.0" | |
| 4799 | - | ||
| 4800 | - | [[patch.unused]] | |
| 4801 | - | name = "quasi-http" | |
| 4802 | - | version = "0.99.0" | |
| 4803 | - | ||
| 4804 | - | [[patch.unused]] | |
| 4805 | - | name = "quasi-immediate" | |
| 4806 | - | version = "0.99.0" | |
| 4807 | - | ||
| 4808 | - | [[patch.unused]] | |
| 4809 | - | name = "quasi-notifs" | |
| 4810 | - | version = "0.99.0" | |
| 4811 | - | ||
| 4812 | - | [[patch.unused]] | |
| 4813 | - | name = "quasi-router" | |
| 4814 | - | version = "0.99.0" | |
| 4815 | - | ||
| 4816 | - | [[patch.unused]] | |
| 4817 | - | name = "quasi-store" | |
| 4818 | - | version = "0.1.0" | |
| 4819 | - | ||
| 4820 | - | [[patch.unused]] | |
| 4821 | - | name = "quasi-tauri" | |
| 4822 | - | version = "0.99.0" | |
| 4823 | - | ||
| 4824 | - | [[patch.unused]] | |
| 4825 | - | name = "quasi-webview" | |
| 4826 | - | version = "0.99.0" | |
| 4827 | - | ||
| 4828 | - | [[patch.unused]] | |
| 4829 | - | name = "docengine" | |
| 4830 | - | version = "0.7.0" | |
| 4831 | - | ||
| 4832 | - | [[patch.unused]] | |
| 4833 | - | name = "quasi-type" | |
| 4834 | - | version = "0.1.3" | |
| 4835 | - | ||
| 4836 | - | [[patch.unused]] | |
| 4837 | - | name = "makeover-build" | |
| 4838 | - | version = "0.66.0" | |
| 4839 | - | ||
| 4840 | - | [[patch.unused]] | |
| 4841 | - | name = "makeover-immediate" | |
| 4842 | - | version = "0.45.0" | |
| 4843 | - | ||
| 4844 | - | [[patch.unused]] | |
| 4845 | - | name = "makeover-touch" | |
| 4846 | - | version = "0.34.0" | |
| 4847 | - | ||
| 4848 | - | [[patch.unused]] | |
| 4849 | - | name = "makeover-webview" | |
| 4850 | - | version = "0.73.0" | |
| 4851 | - | ||
| 4852 | 4852 | [[patch.unused]] | |
| 4853 | 4853 | name = "synckit-config" | |
| 4854 | 4854 | version = "0.2.0" |
| @@ -1,6 +1,6 @@ | |||
| 1 | 1 | [package] | |
| 2 | 2 | name = "mnw-cli" | |
| 3 | - | version = "0.1.4" | |
| 3 | + | version = "0.1.5" | |
| 4 | 4 | edition = "2024" | |
| 5 | 5 | license = "LicenseRef-PolyForm-Noncommercial-1.0.0" | |
| 6 | 6 |
| @@ -5270,7 +5270,7 @@ | |||
| 5270 | 5270 | ||
| 5271 | 5271 | [[package]] | |
| 5272 | 5272 | name = "makenotwork" | |
| 5273 | - | version = "0.16.4" | |
| 5273 | + | version = "0.16.5" | |
| 5274 | 5274 | dependencies = [ | |
| 5275 | 5275 | "anyhow", | |
| 5276 | 5276 | "apple-codesign", | |
| @@ -10767,6 +10767,22 @@ | |||
| 10767 | 10767 | "pkg-config", | |
| 10768 | 10768 | ] | |
| 10769 | 10769 | ||
| 10770 | + | [[patch.unused]] | |
| 10771 | + | name = "quasi-immediate" | |
| 10772 | + | version = "0.103.0" | |
| 10773 | + | ||
| 10774 | + | [[patch.unused]] | |
| 10775 | + | name = "quasi-notifs" | |
| 10776 | + | version = "0.103.0" | |
| 10777 | + | ||
| 10778 | + | [[patch.unused]] | |
| 10779 | + | name = "quasi-store" | |
| 10780 | + | version = "0.1.0" | |
| 10781 | + | ||
| 10782 | + | [[patch.unused]] | |
| 10783 | + | name = "quasi-tauri" | |
| 10784 | + | version = "0.103.0" | |
| 10785 | + | ||
| 10770 | 10786 | [[patch.unused]] | |
| 10771 | 10787 | name = "kberg" | |
| 10772 | 10788 | version = "0.1.0" | |
| @@ -10786,19 +10802,3 @@ | |||
| 10786 | 10802 | [[patch.unused]] | |
| 10787 | 10803 | name = "synckit-config" | |
| 10788 | 10804 | version = "0.2.0" | |
| 10789 | - | ||
| 10790 | - | [[patch.unused]] | |
| 10791 | - | name = "quasi-immediate" | |
| 10792 | - | version = "0.103.0" | |
| 10793 | - | ||
| 10794 | - | [[patch.unused]] | |
| 10795 | - | name = "quasi-notifs" | |
| 10796 | - | version = "0.103.0" | |
| 10797 | - | ||
| 10798 | - | [[patch.unused]] | |
| 10799 | - | name = "quasi-store" | |
| 10800 | - | version = "0.1.0" | |
| 10801 | - | ||
| 10802 | - | [[patch.unused]] | |
| 10803 | - | name = "quasi-tauri" | |
| 10804 | - | version = "0.103.0" |
| @@ -1,6 +1,6 @@ | |||
| 1 | 1 | [package] | |
| 2 | 2 | name = "makenotwork" | |
| 3 | - | version = "0.16.4" | |
| 3 | + | version = "0.16.5" | |
| 4 | 4 | edition = "2024" | |
| 5 | 5 | license = "LicenseRef-PolyForm-Noncommercial-1.0.0" | |
| 6 | 6 | # Server binary: never published to a registry. Marks the crate private so |
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | "license": { | |
| 7 | 7 | "name": "PolyForm Noncommercial 1.0.0" | |
| 8 | 8 | }, | |
| 9 | - | "version": "0.16.4" | |
| 9 | + | "version": "0.16.5" | |
| 10 | 10 | }, | |
| 11 | 11 | "paths": { | |
| 12 | 12 | "/api/git/{owner}/{repo}/notes": { |
| @@ -11,13 +11,13 @@ | |||
| 11 | 11 | //! <!-- wiki: mnw-cli-overview --> | |
| 12 | 12 | ||
| 13 | 13 | mod api; | |
| 14 | + | mod artifact; | |
| 14 | 15 | mod commands; | |
| 15 | 16 | mod config; | |
| 16 | 17 | mod currency; | |
| 17 | 18 | mod format; | |
| 18 | 19 | mod ota; | |
| 19 | 20 | mod rate_limit; | |
| 20 | - | mod rpm; | |
| 21 | 21 | mod ssh; | |
| 22 | 22 | mod staging; | |
| 23 | 23 | mod tls; | |
| @@ -63,8 +63,8 @@ | |||
| 63 | 63 | } | |
| 64 | 64 | // Same shape as `ota` above: an operator one-shot, routed off argv before | |
| 65 | 65 | // the SSH daemon starts. | |
| 66 | - | if argv.get(1).map(String::as_str) == Some("rpm") { | |
| 67 | - | return rpm::run(&argv[2..]).await; | |
| 66 | + | if argv.get(1).map(String::as_str) == Some("artifact") { | |
| 67 | + | return artifact::run(&argv[2..]).await; | |
| 68 | 68 | } | |
| 69 | 69 | ||
| 70 | 70 | tracing_subscriber::fmt() |
| @@ -1042,8 +1042,8 @@ | |||
| 1042 | 1042 | storage: None, | |
| 1043 | 1043 | synckit_storage: None, | |
| 1044 | 1044 | public_storage: None, | |
| 1045 | - | rpm_storage: None, | |
| 1046 | - | rpm_base_url: None, | |
| 1045 | + | artifact_storage: None, | |
| 1046 | + | artifact_base_url: None, | |
| 1047 | 1047 | stripe: None, | |
| 1048 | 1048 | admin_user_id: Some(user.id), | |
| 1049 | 1049 | synckit_jwt_secret: None, | |
| @@ -1128,8 +1128,8 @@ | |||
| 1128 | 1128 | storage: None, | |
| 1129 | 1129 | synckit_storage: None, | |
| 1130 | 1130 | public_storage: None, | |
| 1131 | - | rpm_storage: None, | |
| 1132 | - | rpm_base_url: None, | |
| 1131 | + | artifact_storage: None, | |
| 1132 | + | artifact_base_url: None, | |
| 1133 | 1133 | stripe: None, | |
| 1134 | 1134 | admin_user_id: None, | |
| 1135 | 1135 | synckit_jwt_secret: None, |
| @@ -28,22 +28,29 @@ | |||
| 28 | 28 | /// overridden by `S3_PUBLIC_BUCKET`. Required in production (the CDN serves | |
| 29 | 29 | /// ONLY this bucket); `None` in dev when `S3_PUBLIC_BUCKET` is unset. | |
| 30 | 30 | pub public_storage: Option<StorageConfig>, | |
| 31 | - | /// Bucket holding the Alloy hotfix RPM repository: the `.rpm` files and the | |
| 32 | - | /// `createrepo_c` metadata that `dnf`/`rpm-ostree` fetch by path. Served | |
| 33 | - | /// beside the server by a GET/HEAD-only Caddy block, exactly as the CDN | |
| 34 | - | /// bucket is, so a published fix reaches machines with no deploy at all. | |
| 31 | + | /// Bucket holding the artifact store. Three prefixes, one bucket: the Alloy | |
| 32 | + | /// hotfix RPM repository that `dnf`/`rpm-ostree` fetch by path, the mirror | |
| 33 | + | /// of the Fedora base images, and the locked snapshot of the layered RPM | |
| 34 | + | /// set. Served by a GET/HEAD-only Caddy block, exactly as the CDN bucket is, | |
| 35 | + | /// so a published fix reaches machines with no deploy at all. | |
| 35 | 36 | /// | |
| 36 | - | /// Resolved from `RPM_S3_*` when a dedicated credential is provisioned, and | |
| 37 | + | /// That Caddy block belongs on a box that serves nothing else. One | |
| 38 | + | /// outward-facing purpose per production machine, so a pull spike here | |
| 39 | + | /// never lands on the machine serving paying creators. See wiki | |
| 40 | + | /// `mnw-package-hosting`. | |
| 41 | + | /// | |
| 42 | + | /// Resolved from `ARTIFACT_S3_*` when a dedicated credential is provisioned, and | |
| 37 | 43 | /// otherwise from the main storage with the bucket overridden by | |
| 38 | - | /// `S3_RPM_BUCKET`. `None` when neither is set, which is every dev | |
| 44 | + | /// `S3_ARTIFACT_BUCKET`. `None` when neither is set, which is every dev | |
| 39 | 45 | /// environment; the publish endpoint then answers 503 rather than 404, so | |
| 40 | 46 | /// "not configured here" never reads as "the route is gone". | |
| 41 | - | pub rpm_storage: Option<StorageConfig>, | |
| 42 | - | /// Public render base for [`Self::rpm_storage`] (e.g. | |
| 43 | - | /// `https://rpm.makenot.work`), the host the Caddy block answers on. Only | |
| 47 | + | pub artifact_storage: Option<StorageConfig>, | |
| 48 | + | /// Public render base for [`Self::artifact_storage`] (e.g. | |
| 49 | + | /// `https://artifacts.makenot.work`), the host the Caddy block answers on. | |
| 50 | + | /// Only | |
| 44 | 51 | /// used to tell an operator where a published object landed; nothing | |
| 45 | - | /// durable is written from it. `None` when `RPM_BASE_URL` is unset. | |
| 46 | - | pub rpm_base_url: Option<String>, | |
| 52 | + | /// durable is written from it. `None` when `ARTIFACT_BASE_URL` is unset. | |
| 53 | + | pub artifact_base_url: Option<String>, | |
| 47 | 54 | /// Stripe payment configuration (optional) | |
| 48 | 55 | pub stripe: Option<StripeConfig>, | |
| 49 | 56 | /// Admin user ID for waitlist management (optional) | |
| @@ -280,13 +287,13 @@ | |||
| 280 | 287 | }) | |
| 281 | 288 | }); | |
| 282 | 289 | ||
| 283 | - | // The RPM repo bucket. Two ways in, and the prefixed one wins: a | |
| 284 | - | // dedicated `RPM_S3_*` credential is the shape the provisioning task | |
| 285 | - | // (alloy `23f599d9`) hands over, and `S3_RPM_BUCKET` over the main | |
| 290 | + | // The artifact store bucket. Two ways in, and the prefixed one wins: a | |
| 291 | + | // dedicated `ARTIFACT_S3_*` credential is the shape the provisioning task | |
| 292 | + | // (alloy `23f599d9`) hands over, and `S3_ARTIFACT_BUCKET` over the main | |
| 286 | 293 | // credentials is the same fallback `public_storage` takes above, so a | |
| 287 | 294 | // bucket in the same project needs one variable rather than five. | |
| 288 | - | let rpm_storage = StorageConfig::from_env_prefixed("RPM_S3_").or_else(|| { | |
| 289 | - | std::env::var("S3_RPM_BUCKET") | |
| 295 | + | let artifact_storage = StorageConfig::from_env_prefixed("ARTIFACT_S3_").or_else(|| { | |
| 296 | + | std::env::var("S3_ARTIFACT_BUCKET") | |
| 290 | 297 | .ok() | |
| 291 | 298 | .filter(|s| !s.is_empty()) | |
| 292 | 299 | .and_then(|bucket| { | |
| @@ -297,7 +304,7 @@ | |||
| 297 | 304 | }) | |
| 298 | 305 | }); | |
| 299 | 306 | ||
| 300 | - | let rpm_base_url = std::env::var("RPM_BASE_URL") | |
| 307 | + | let artifact_base_url = std::env::var("ARTIFACT_BASE_URL") | |
| 301 | 308 | .ok() | |
| 302 | 309 | .filter(|s| !s.is_empty()) | |
| 303 | 310 | .map(|s| s.trim_end_matches('/').to_string()); | |
| @@ -524,8 +531,8 @@ | |||
| 524 | 531 | storage, | |
| 525 | 532 | synckit_storage, | |
| 526 | 533 | public_storage, | |
| 527 | - | rpm_storage, | |
| 528 | - | rpm_base_url, | |
| 534 | + | artifact_storage, | |
| 535 | + | artifact_base_url, | |
| 529 | 536 | stripe, | |
| 530 | 537 | admin_user_id, | |
| 531 | 538 | synckit_jwt_secret, |
| @@ -443,26 +443,30 @@ | |||
| 443 | 443 | pub const OTA_READ_RATE_LIMIT_MS: u64 = 100; | |
| 444 | 444 | pub const OTA_READ_RATE_LIMIT_BURST: u32 = 30; | |
| 445 | 445 | ||
| 446 | - | // Alloy hotfix RPM repo publishing (routes::rpm). | |
| 447 | - | /// Presign lifetime for an RPM/repodata PUT. Matches the OTA artifact window: | |
| 448 | - | /// the object is uploaded immediately after the mint, and a short window bounds | |
| 446 | + | // Artifact store publishing (routes::artifacts). | |
| 447 | + | /// Presign lifetime for one object's PUT. Matches the OTA artifact window: the | |
| 448 | + | /// object is uploaded immediately after the mint, and a short window bounds | |
| 449 | 449 | /// what a leaked URL is worth. | |
| 450 | - | pub const RPM_PRESIGN_EXPIRY_SECS: u64 = 3600; // 1 hour | |
| 451 | - | /// Largest object the RPM publish endpoint will sign. A single unresumable PUT, | |
| 452 | - | /// so it stays modest; the biggest thing the repo carries is one package, and a | |
| 453 | - | /// package near this size is a packaging mistake rather than a hotfix. | |
| 454 | - | pub const RPM_MAX_OBJECT_BYTES: i64 = 2 * 1024 * 1024 * 1024; // 2 GB | |
| 450 | + | pub const ARTIFACT_PRESIGN_EXPIRY_SECS: u64 = 3600; // 1 hour | |
| 451 | + | /// Largest object the publish endpoint will sign. A single unresumable PUT, so | |
| 452 | + | /// it stays modest. The biggest thing the store carries is one package or one | |
| 453 | + | /// image layer, and either near this size is a packaging mistake rather than a | |
| 454 | + | /// hotfix. | |
| 455 | + | pub const ARTIFACT_MAX_OBJECT_BYTES: i64 = 2 * 1024 * 1024 * 1024; // 2 GB | |
| 455 | 456 | /// Longest object path the endpoint will accept, counted in bytes over the | |
| 456 | 457 | /// whole key. Well under S3's 1024-byte key limit and far past any real | |
| 457 | - | /// `repodata/<sha256>-primary.xml.zst`. | |
| 458 | - | pub const RPM_MAX_KEY_BYTES: usize = 255; | |
| 459 | - | /// Most path segments an RPM object key may carry: `alloy/f43/x86_64/repodata/repomd.xml` | |
| 460 | - | /// is five. | |
| 461 | - | pub const RPM_MAX_KEY_SEGMENTS: usize = 8; | |
| 462 | - | // RPM publish: burst 20, then 4/sec. A repodata push is several objects back to | |
| 463 | - | // back, so the burst is wider than OTA's while the steady rate stays low. | |
| 464 | - | pub const RPM_WRITE_RATE_LIMIT_MS: u64 = 250; | |
| 465 | - | pub const RPM_WRITE_RATE_LIMIT_BURST: u32 = 20; | |
| 458 | + | /// `repodata/<sha256>-primary.xml.zst` or `blobs/sha256/<digest>`. | |
| 459 | + | pub const ARTIFACT_MAX_KEY_BYTES: usize = 255; | |
| 460 | + | /// Most path segments an object key may carry. | |
| 461 | + | /// `alloy/hotfix/f43/x86_64/repodata/repomd.xml` is six, and an OCI layout's | |
| 462 | + | /// `alloy/base/fedora-bootc/43/x86_64/blobs/sha256/<digest>` is eight, which is | |
| 463 | + | /// what sets this rather than the RPM side. | |
| 464 | + | pub const ARTIFACT_MAX_KEY_SEGMENTS: usize = 10; | |
| 465 | + | // Artifact publish: burst 20, then 4/sec. A repodata push or a layout's blob | |
| 466 | + | // set is several objects back to back, so the burst is wider than OTA's while | |
| 467 | + | // the steady rate stays low. | |
| 468 | + | pub const ARTIFACT_WRITE_RATE_LIMIT_MS: u64 = 250; | |
| 469 | + | pub const ARTIFACT_WRITE_RATE_LIMIT_BURST: u32 = 20; | |
| 466 | 470 | ||
| 467 | 471 | // Build pipeline | |
| 468 | 472 | pub const BUILD_TIMEOUT_SECS: u64 = 1800; // 30 min |
| @@ -103,8 +103,8 @@ | |||
| 103 | 103 | use email::EmailClient; | |
| 104 | 104 | use payments::{PaymentCapabilities, PaymentProvider}; | |
| 105 | 105 | use routes::{ | |
| 106 | - | admin_routes, api_routes, auth_routes, build_routes, git_issue_routes, git_routes, | |
| 107 | - | git_write_routes, oauth_routes, ota_routes, page_routes, postmark_routes, rpm_routes, | |
| 106 | + | admin_routes, api_routes, artifact_routes, auth_routes, build_routes, git_issue_routes, | |
| 107 | + | git_routes, git_write_routes, oauth_routes, ota_routes, page_routes, postmark_routes, | |
| 108 | 108 | sso_routes, storage_routes, stripe_routes, synckit_routes, | |
| 109 | 109 | }; | |
| 110 | 110 | use scanning::ScanPipeline; | |
| @@ -184,11 +184,13 @@ | |||
| 184 | 184 | /// gallery, item/project images); the scan worker copies Clean image | |
| 185 | 185 | /// objects here cross-bucket. `None` when `S3_PUBLIC_BUCKET` is unset. | |
| 186 | 186 | pub public_s3: Option<Arc<dyn StorageBackend>>, | |
| 187 | - | /// Bucket holding the Alloy hotfix RPM repository. Written only by the | |
| 188 | - | /// admin publish endpoint (`routes::rpm`); read by nobody here, because the | |
| 189 | - | /// repo is fetched straight off the bucket through Caddy. `None` when the | |
| 190 | - | /// bucket is unconfigured, which is every dev environment. | |
| 191 | - | pub rpm_s3: Option<Arc<dyn StorageBackend>>, | |
| 187 | + | /// Bucket holding the artifact store: the Alloy hotfix RPM repository, the | |
| 188 | + | /// Fedora base image mirror, and the locked layered RPM set, one prefix | |
| 189 | + | /// each. Written only by the admin publish endpoint (`routes::artifacts`); | |
| 190 | + | /// read by nobody here, because a client fetches straight off the bucket | |
| 191 | + | /// through Caddy. `None` when the bucket is unconfigured, which is every | |
| 192 | + | /// dev environment. | |
| 193 | + | pub artifact_s3: Option<Arc<dyn StorageBackend>>, | |
| 192 | 194 | } | |
| 193 | 195 | ||
| 194 | 196 | /// Derived in-memory caches held by [`AppState`]. All are `Arc<DashMap>` so a | |
| @@ -458,10 +460,10 @@ | |||
| 458 | 460 | }) | |
| 459 | 461 | } | |
| 460 | 462 | ||
| 461 | - | /// Get the RPM-repo S3 storage backend, or error if not configured. | |
| 462 | - | pub fn require_rpm_s3(&self) -> error::Result<&Arc<dyn StorageBackend>> { | |
| 463 | - | self.rpm_s3.as_ref().ok_or_else(|| { | |
| 464 | - | error::AppError::ServiceUnavailable("RPM bucket is not configured".to_string()) | |
| 463 | + | /// Get the artifact-store S3 storage backend, or error if not configured. | |
| 464 | + | pub fn require_artifact_s3(&self) -> error::Result<&Arc<dyn StorageBackend>> { | |
| 465 | + | self.artifact_s3.as_ref().ok_or_else(|| { | |
| 466 | + | error::AppError::ServiceUnavailable("artifact bucket is not configured".to_string()) | |
| 465 | 467 | }) | |
| 466 | 468 | } | |
| 467 | 469 | } | |
| @@ -582,7 +584,7 @@ | |||
| 582 | 584 | .merge(git_issue_routes()) | |
| 583 | 585 | .merge(git_write_routes()) | |
| 584 | 586 | .merge(ota_routes()) | |
| 585 | - | .merge(rpm_routes()) | |
| 587 | + | .merge(artifact_routes()) | |
| 586 | 588 | .merge(build_routes()); | |
| 587 | 589 | // The description layer, when a screen is switched on. Inside the CSRF tree | |
| 588 | 590 | // rather than beside it, so a described write is covered by the same |
| @@ -394,25 +394,22 @@ | |||
| 394 | 394 | // Initialize the RPM-repo bucket client if configured. Written only by the | |
| 395 | 395 | // admin publish endpoint; served to dnf/rpm-ostree by Caddy off the bucket, | |
| 396 | 396 | // so nothing here reads it back. | |
| 397 | - | let rpm_s3: Option<std::sync::Arc<dyn makenotwork::storage::StorageBackend>> = if let Some( | |
| 398 | - | ref rpm_storage_config, | |
| 399 | - | ) = | |
| 400 | - | config.rpm_storage | |
| 401 | - | { | |
| 402 | - | match S3Client::new(rpm_storage_config, &config.host_url).await { | |
| 403 | - | Ok(client) => { | |
| 404 | - | tracing::info!(bucket = %rpm_storage_config.bucket, "RPM S3 bucket initialized"); | |
| 405 | - | Some(std::sync::Arc::new(client)) | |
| 397 | + | let artifact_s3: Option<std::sync::Arc<dyn makenotwork::storage::StorageBackend>> = | |
| 398 | + | if let Some(ref rpm_storage_config) = config.artifact_storage { | |
| 399 | + | match S3Client::new(rpm_storage_config, &config.host_url).await { | |
| 400 | + | Ok(client) => { | |
| 401 | + | tracing::info!(bucket = %rpm_storage_config.bucket, "RPM S3 bucket initialized"); | |
| 402 | + | Some(std::sync::Arc::new(client)) | |
| 403 | + | } | |
| 404 | + | Err(e) => { | |
| 405 | + | tracing::warn!(error = ?e, "Failed to initialize RPM S3 bucket"); | |
| 406 | + | None | |
| 407 | + | } | |
| 406 | 408 | } | |
| 407 | - | Err(e) => { | |
| 408 | - | tracing::warn!(error = ?e, "Failed to initialize RPM S3 bucket"); | |
| 409 | - | None | |
| 410 | - | } | |
| 411 | - | } | |
| 412 | - | } else { | |
| 413 | - | tracing::info!("RPM S3 bucket not configured"); | |
| 414 | - | None | |
| 415 | - | }; | |
| 409 | + | } else { | |
| 410 | + | tracing::info!("RPM S3 bucket not configured"); | |
| 411 | + | None | |
| 412 | + | }; | |
| 416 | 413 | ||
| 417 | 414 | // Initialize Stripe client if configured. Stripe implements every | |
| 418 | 415 | // capability extension, so one `Arc` becomes both the base provider and | |
| @@ -574,7 +571,7 @@ | |||
| 574 | 571 | s3, | |
| 575 | 572 | synckit_s3, | |
| 576 | 573 | public_s3, | |
| 577 | - | rpm_s3, | |
| 574 | + | artifact_s3, | |
| 578 | 575 | }, | |
| 579 | 576 | payments: stripe, | |
| 580 | 577 | payment_caps, |