tensorfs 0.3.73__tar.gz → 0.3.75__tar.gz
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.
- {tensorfs-0.3.73 → tensorfs-0.3.75}/Cargo.lock +2 -2
- {tensorfs-0.3.73 → tensorfs-0.3.75}/Cargo.toml +1 -1
- {tensorfs-0.3.73 → tensorfs-0.3.75}/PKG-INFO +1 -1
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/bin/tfs/fetch.rs +2 -3
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/bin/tfs/main.rs +15 -3
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/err.rs +1 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/transport/http.rs +51 -9
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/transport/hub.rs +17 -11
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/transport/mod.rs +1 -1
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/transport/tests.rs +51 -1
- tensorfs-0.3.75/crates/tensorfs-core/tests/hub_tls.rs +124 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-py/src/store.rs +3 -3
- {tensorfs-0.3.73 → tensorfs-0.3.75}/pyproject.toml +1 -1
- {tensorfs-0.3.73 → tensorfs-0.3.75}/python/tensorfs/_ext.pyi +1 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/python/tensorfs/errors.py +2 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/Cargo.toml +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/build.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/examples/h3-swiglu-layout.md +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/examples/optional-cache-backfill.md +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/examples/resident-conversion.md +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/examples/resident_conversion_profile.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/asset_update.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/b64.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/bin/tfs/ckpt.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/bin/tfs/conform.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/bin/tfs/ingest.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/bin/tfs/rd.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/bin/tfs/repo.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/bin/tfs/snap.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/bin/tfs/watch.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/cache_roots.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/canon.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/capability.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/catalog/lock.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/catalog.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/cbor.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/checkpoint.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/checkpoint_root.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/corpus.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/derived/adoption.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/derived/companion_tests.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/derived/estimate.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/derived/graft_tests.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/derived/group_commit_tests.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/derived/history_cost_tests.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/derived/part_rows_tests.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/derived/progress.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/derived/resume_tests.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/derived/retention.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/derived/roots.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/derived.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/descriptors.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/disk.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/dtype.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/durability.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/fetch.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/fill.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/fit.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/gc.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/header.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/home.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/ids.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/ingest/carrier.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/ingest/convert.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/ingest/custody.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/ingest/fingerprint.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/ingest/gguf.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/ingest/h3_lora.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/ingest/journal.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/ingest/mod.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/ingest/narrow.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/ingest/preflight.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/ingest/routes/sdxl.routes.json +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/ingest/routes/sdxl.spec.json +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/ingest/routes.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/ingest/source.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/ingest/stamp.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/ingest/transaction.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/jcs.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/lib.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/limits.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/machine.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/manifest.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/meta.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/project.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/providers.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/read.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/receipt.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/reclaim.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/registry.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/relation.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/repo_cache/identity.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/repo_cache.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/repository.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/sha256.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/source_artifact.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/spec.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/staging.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/stats.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/storage.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/store.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/transport/api.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/transport/http_reuse_tests.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/transport/ledger.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/transport/memory.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/transport/pace.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/transport/policy.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/transport/prefix.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/transport/pull.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/transport/push.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/transport/ranged.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/transport/speculate.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/unsynced.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/src/vectors.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/additive_fields.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/anima_hf_profile.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/as_is.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/checkpoint_roots.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/civitai_sdxl_profile.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/fd_budget.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/fd_headroom.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/fetch_url_progress.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/fit.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/fixtures/repo_apply/blobs.jsonl +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_list.jsonl +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_repository.json +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_rows.jsonl +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/fixtures/repo_apply/header.cbor +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/fixtures/repo_apply/manifest.json +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/fixtures/repo_apply/mutation.json +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/foreign_json.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/h3_lora.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/h3_swiglu.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/home.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/import_tree.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/instrument_profiles.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/liveness.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/qwen_image21_profile.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/read_plan.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/reclaim.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/reclaim_run.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/repo_cache.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/repo_store.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/resident_admission.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/routed_single_file.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/sha256_backends.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/sharded_cas.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/source_artifacts.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/source_download.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/source_plan.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/source_prefixes.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/source_preflight.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/staging.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/store_boundaries.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/tensor_schema.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/transfer_memory.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/trust_index.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/version.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/write_through.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-py/Cargo.toml +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-py/src/docs.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-py/src/errors.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-py/src/ingest.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-py/src/lib.rs +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/python/tensorfs/__init__.py +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/python/tensorfs/_derived_channel.py +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/python/tensorfs/_source_channel.py +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/python/tensorfs/_tensors.py +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/python/tensorfs/derived.py +0 -0
- {tensorfs-0.3.73 → tensorfs-0.3.75}/python/tensorfs/py.typed +0 -0
|
@@ -439,7 +439,7 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
|
439
439
|
|
|
440
440
|
[[package]]
|
|
441
441
|
name = "tensorfs-core"
|
|
442
|
-
version = "0.3.
|
|
442
|
+
version = "0.3.75"
|
|
443
443
|
dependencies = [
|
|
444
444
|
"fs2",
|
|
445
445
|
"libc",
|
|
@@ -454,7 +454,7 @@ dependencies = [
|
|
|
454
454
|
|
|
455
455
|
[[package]]
|
|
456
456
|
name = "tensorfs-py"
|
|
457
|
-
version = "0.3.
|
|
457
|
+
version = "0.3.75"
|
|
458
458
|
dependencies = [
|
|
459
459
|
"pyo3",
|
|
460
460
|
"tensorfs-core",
|
|
@@ -192,9 +192,8 @@ fn deadline_of(flags: &Flags) -> Deadline {
|
|
|
192
192
|
|
|
193
193
|
/// The ONE credential spelling, reaching the child explicitly (tfs-050): `--credential-file
|
|
194
194
|
/// <path>` or the deliberately-set `TFS_CREDENTIAL` — never argv (world-readable in /proc),
|
|
195
|
-
/// never the inherited environment at large. The value is `bearer <token
|
|
196
|
-
/// exactly the named hosts, or empty for anonymous
|
|
197
|
-
/// the hub's closure and presign routes taking no credential at all.
|
|
195
|
+
/// never the inherited environment at large. The value is `bearer <token>` or
|
|
196
|
+
/// `worker <id> <token>`, scoped to exactly the named hosts, or empty for anonymous.
|
|
198
197
|
fn credential_of(
|
|
199
198
|
flags: &Flags,
|
|
200
199
|
hosts: Vec<String>,
|
|
@@ -39,9 +39,10 @@
|
|
|
39
39
|
//! tfs fill <root> <plan> resumable fill: skip only verified objects
|
|
40
40
|
//!
|
|
41
41
|
//! The ONE transport (tfs-048/tfs-049/tfs-050). The credential is `--credential-file` or
|
|
42
|
-
//! TFS_CREDENTIAL (`bearer <token>`, or empty for anonymous), never
|
|
43
|
-
//! URL of `-` arrives on stdin. Flags: --hub <base> --lane --session --streams <n>
|
|
44
|
-
//! --streams-start <n> --timeout <s> --allow-hosts a,b,.c --allow-local --max-redirects <n
|
|
42
|
+
//! TFS_CREDENTIAL (`bearer <token>`, `worker <id> <token>`, or empty for anonymous), never
|
|
43
|
+
//! bare argv; a URL of `-` arrives on stdin. Flags: --hub <base> --lane --session --streams <n>
|
|
44
|
+
//! --streams-start <n> --timeout <s> --allow-hosts a,b,.c --allow-local --max-redirects <n>
|
|
45
|
+
//! --ca-file <pem> (a private hub's CA, trusted beside the webpki set).
|
|
45
46
|
//! `--streams` is the most objects in flight (default 128, memory-bounded); the walk starts
|
|
46
47
|
//! at `--streams-start` (default 16) and doubles while measured goodput follows.
|
|
47
48
|
//! `tfs fetch` reads and backfills the Store's bound repo cache between the local Store
|
|
@@ -202,6 +203,17 @@ fn accept_printed_ids(args: Vec<String>) -> Vec<String> {
|
|
|
202
203
|
|
|
203
204
|
fn main() -> ExitCode {
|
|
204
205
|
let (args, flags) = split_flags(std::env::args().skip(1).collect());
|
|
206
|
+
if let Some(path) = flag(&flags, "ca-file") {
|
|
207
|
+
let trusted = fs::read(path)
|
|
208
|
+
.map_err(|e| format!("IO_FAILED: read {path}: {e}"))
|
|
209
|
+
.and_then(|pem| {
|
|
210
|
+
tensorfs_core::transport::trust_roots(&pem).map_err(|r| format!("{r} ({path})"))
|
|
211
|
+
});
|
|
212
|
+
if let Err(refusal) = trusted {
|
|
213
|
+
eprintln!("REFUSED {refusal}");
|
|
214
|
+
return ExitCode::FAILURE;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
205
217
|
let args = accept_printed_ids(args);
|
|
206
218
|
let a: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
|
|
207
219
|
match a.as_slice() {
|
|
@@ -30,10 +30,11 @@
|
|
|
30
30
|
use crate::err::{refuse, Code, Refusal, Result};
|
|
31
31
|
use crate::transport::ledger::{Deadline, Ledger};
|
|
32
32
|
use crate::transport::policy::CheckedUrl;
|
|
33
|
+
use rustls::pki_types::pem::PemObject;
|
|
33
34
|
use rustls::pki_types::{CertificateDer, ServerName};
|
|
34
35
|
use std::io::{ErrorKind, Read, Write};
|
|
35
36
|
use std::net::TcpStream;
|
|
36
|
-
use std::sync::{Arc, Mutex};
|
|
37
|
+
use std::sync::{Arc, Mutex, OnceLock};
|
|
37
38
|
use std::time::{Duration, Instant};
|
|
38
39
|
|
|
39
40
|
const HEAD_MAX_BYTES: usize = 64 * 1024;
|
|
@@ -211,13 +212,35 @@ struct Idle {
|
|
|
211
212
|
wire: Wire,
|
|
212
213
|
}
|
|
213
214
|
|
|
215
|
+
/// Authorities this process trusts beside the webpki set: a private hub's CA, named by its
|
|
216
|
+
/// caller as a location (`tfs --ca-file`). Set once, before the first exchange.
|
|
217
|
+
static EXTRA_ROOTS: OnceLock<Vec<CertificateDer<'static>>> = OnceLock::new();
|
|
218
|
+
|
|
219
|
+
/// Trust the PEM certificates in `pem` for every client this process builds.
|
|
220
|
+
pub fn trust_roots(pem: &[u8]) -> Result<usize> {
|
|
221
|
+
let roots: Vec<_> = CertificateDer::pem_slice_iter(pem)
|
|
222
|
+
.collect::<std::result::Result<_, _>>()
|
|
223
|
+
.map_err(|e| Refusal {
|
|
224
|
+
code: Code::UNKNOWN_FORMAT,
|
|
225
|
+
detail: format!("not a PEM certificate bundle: {e}"),
|
|
226
|
+
})?;
|
|
227
|
+
let (usable, _) = rustls::RootCertStore::empty().add_parsable_certificates(roots.clone());
|
|
228
|
+
if roots.is_empty() || usable != roots.len() {
|
|
229
|
+
return refuse(Code::UNKNOWN_FORMAT, "holds no usable CA certificate");
|
|
230
|
+
}
|
|
231
|
+
EXTRA_ROOTS.set(roots).map_err(|_| Refusal {
|
|
232
|
+
code: Code::UNKNOWN_FORMAT,
|
|
233
|
+
detail: "this process already chose its trust roots".into(),
|
|
234
|
+
})?;
|
|
235
|
+
Ok(usable)
|
|
236
|
+
}
|
|
237
|
+
|
|
214
238
|
impl Client {
|
|
215
239
|
pub fn new() -> Client {
|
|
216
|
-
Client::with_extra_roots(&[])
|
|
240
|
+
Client::with_extra_roots(EXTRA_ROOTS.get().map_or(&[], Vec::as_slice))
|
|
217
241
|
}
|
|
218
242
|
|
|
219
|
-
///
|
|
220
|
-
/// self-signed authority; production callers pass none and trust the webpki set.
|
|
243
|
+
/// Trusts the webpki set plus `extra_roots`.
|
|
221
244
|
pub fn with_extra_roots(extra_roots: &[CertificateDer<'static>]) -> Client {
|
|
222
245
|
let mut roots = rustls::RootCertStore::empty();
|
|
223
246
|
roots.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
|
|
@@ -482,7 +505,9 @@ fn connect(
|
|
|
482
505
|
)
|
|
483
506
|
}
|
|
484
507
|
|
|
508
|
+
#[allow(clippy::too_many_arguments)]
|
|
485
509
|
fn tls_handshake(
|
|
510
|
+
host: &str,
|
|
486
511
|
sock: &mut TcpStream,
|
|
487
512
|
conn: &mut rustls::ClientConnection,
|
|
488
513
|
deadline: Deadline,
|
|
@@ -516,10 +541,18 @@ fn tls_handshake(
|
|
|
516
541
|
Ok(0) => return refuse(fail, "origin closed the connection mid-handshake"),
|
|
517
542
|
Ok(_) => {
|
|
518
543
|
advanced = Instant::now();
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
544
|
+
// A certificate or protocol verdict is this client's, and re-asking reaches
|
|
545
|
+
// it again: refused typed, never retried as weather. The alert goes out so
|
|
546
|
+
// the origin logs why.
|
|
547
|
+
if let Err(e) = conn.process_new_packets() {
|
|
548
|
+
let _ = conn.write_tls(sock);
|
|
549
|
+
return refuse(
|
|
550
|
+
Code::TLS_UNTRUSTED,
|
|
551
|
+
format!(
|
|
552
|
+
"{host}: TLS refused: {e}; a private hub names its CA with --ca-file"
|
|
553
|
+
),
|
|
554
|
+
);
|
|
555
|
+
}
|
|
523
556
|
}
|
|
524
557
|
Err(e) if would_block(&e) => {
|
|
525
558
|
stream_verdict(judge, ledger, advanced, "TLS handshake")?;
|
|
@@ -1041,7 +1074,16 @@ pub fn send<'l>(
|
|
|
1041
1074
|
})?;
|
|
1042
1075
|
let mut sock = sock;
|
|
1043
1076
|
let mut conn = Box::new(conn);
|
|
1044
|
-
tls_handshake(
|
|
1077
|
+
tls_handshake(
|
|
1078
|
+
&checked.host,
|
|
1079
|
+
&mut sock,
|
|
1080
|
+
&mut conn,
|
|
1081
|
+
deadline,
|
|
1082
|
+
ledger,
|
|
1083
|
+
judge,
|
|
1084
|
+
opened,
|
|
1085
|
+
fail,
|
|
1086
|
+
)?;
|
|
1045
1087
|
Wire::Tls { sock, conn }
|
|
1046
1088
|
} else {
|
|
1047
1089
|
Wire::Plain(sock)
|
|
@@ -36,9 +36,10 @@
|
|
|
36
36
|
//! **The credential arrives as a provider trait, never a credential type**, so one
|
|
37
37
|
//! implementation serves whatever a caller holds. It is asked per host, so a credential
|
|
38
38
|
//! stays scoped to the hosts its provider names and cannot leak onto a presigned object
|
|
39
|
-
//! host or a redirect target.
|
|
40
|
-
//!
|
|
41
|
-
//!
|
|
39
|
+
//! host or a redirect target. Published checkpoints need none; a machine reads its
|
|
40
|
+
//! owner's unpublished checkpoints by presenting its worker capability
|
|
41
|
+
//! (`worker <id> <token>` → `x-cozy-worker-id` + `x-cozy-worker-token`), which the hub
|
|
42
|
+
//! scopes to the machine owner's account.
|
|
42
43
|
|
|
43
44
|
use crate::canon::{self, as_arr, as_obj, as_str, as_uint, Value};
|
|
44
45
|
use crate::err::{refuse, Code, Refusal, Result};
|
|
@@ -103,9 +104,10 @@ impl CredentialProvider for ScopedHeaders {
|
|
|
103
104
|
/// The ONE credential spelling every surface passes (tfs-050): exactly one scoped value,
|
|
104
105
|
/// handed explicitly — a file, one deliberately-set variable — never inherited.
|
|
105
106
|
///
|
|
106
|
-
/// - `bearer <token>`
|
|
107
|
-
/// -
|
|
108
|
-
/// presign
|
|
107
|
+
/// - `bearer <token>` → `authorization: Bearer <token>`
|
|
108
|
+
/// - `worker <id> <token>` → `x-cozy-worker-id` + `x-cozy-worker-token`: a machine's
|
|
109
|
+
/// worker capability, which the hub's closure and presign read as its owner's grant
|
|
110
|
+
/// - empty → anonymous: published checkpoints only.
|
|
109
111
|
pub fn credential_from_spec(spec: &str, hosts: Vec<String>) -> Result<ScopedHeaders> {
|
|
110
112
|
let spec = spec.trim();
|
|
111
113
|
if spec.is_empty() {
|
|
@@ -114,16 +116,20 @@ pub fn credential_from_spec(spec: &str, hosts: Vec<String>) -> Result<ScopedHead
|
|
|
114
116
|
headers: Vec::new(),
|
|
115
117
|
});
|
|
116
118
|
}
|
|
117
|
-
let
|
|
118
|
-
let headers = match
|
|
119
|
-
|
|
119
|
+
let parts: Vec<&str> = spec.split_whitespace().collect();
|
|
120
|
+
let headers = match parts.as_slice() {
|
|
121
|
+
["bearer", token] => {
|
|
120
122
|
vec![("authorization".to_string(), format!("Bearer {token}"))]
|
|
121
123
|
}
|
|
124
|
+
["worker", id, token] => vec![
|
|
125
|
+
("x-cozy-worker-id".to_string(), id.to_string()),
|
|
126
|
+
("x-cozy-worker-token".to_string(), token.to_string()),
|
|
127
|
+
],
|
|
122
128
|
_ => {
|
|
123
129
|
return refuse(
|
|
124
130
|
Code::CREDENTIAL_REQUIRED,
|
|
125
|
-
"a credential is `bearer <token>` or empty — one
|
|
126
|
-
explicitly",
|
|
131
|
+
"a credential is `bearer <token>`, `worker <id> <token>` or empty — one \
|
|
132
|
+
scoped value, passed explicitly",
|
|
127
133
|
)
|
|
128
134
|
}
|
|
129
135
|
};
|
|
@@ -49,7 +49,7 @@ mod speculate;
|
|
|
49
49
|
mod tests;
|
|
50
50
|
|
|
51
51
|
pub use api::{api_get, fetch_prefix, probe_length, Prefix};
|
|
52
|
-
pub use http::Client;
|
|
52
|
+
pub use http::{trust_roots, Client};
|
|
53
53
|
pub use hub::{
|
|
54
54
|
closure, closure_all, credential_from_spec, presign, Anonymous, Closure, CredentialProvider,
|
|
55
55
|
HostToken, Presigned, ScopedHeaders,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//! no hub. The ledger tests run at millisecond resolution: the cadence is configuration,
|
|
4
4
|
//! the RULE under test is production's.
|
|
5
5
|
|
|
6
|
-
use super::hub::{Anonymous, HostToken};
|
|
6
|
+
use super::hub::{credential_from_spec, Anonymous, HostToken};
|
|
7
7
|
use super::ledger::{Deadline, Ledger};
|
|
8
8
|
use super::policy::{self, blocked, SourcePolicy};
|
|
9
9
|
use super::pull::{absolute_location, fetch_url, pull, ObjectSource, PullRequest};
|
|
@@ -2134,6 +2134,56 @@ fn credential_headers_reach_the_hub_and_not_the_object_host() {
|
|
|
2134
2134
|
let _ = std::fs::remove_dir_all(root);
|
|
2135
2135
|
}
|
|
2136
2136
|
|
|
2137
|
+
#[test]
|
|
2138
|
+
fn a_worker_capability_reaches_the_hub_calls_as_its_two_headers() {
|
|
2139
|
+
let root = temporary("worker-cred");
|
|
2140
|
+
let store = Store::init(&root).unwrap();
|
|
2141
|
+
let checkpoint = Arc::new(checkpoint(1, 4 * 1024));
|
|
2142
|
+
let checkpoint_for = Arc::clone(&checkpoint);
|
|
2143
|
+
let base_slot: Arc<Mutex<String>> = Arc::default();
|
|
2144
|
+
let dispatch_base = Arc::clone(&base_slot);
|
|
2145
|
+
let dispatch: Dispatch = Arc::new(move |request: &Request| {
|
|
2146
|
+
let base = dispatch_base.lock().unwrap().clone();
|
|
2147
|
+
let machine = request.header("x-cozy-worker-id") == Some("om-machine")
|
|
2148
|
+
&& request.header("x-cozy-worker-token") == Some("worker-token");
|
|
2149
|
+
match (request.method.as_str(), request.path.as_str()) {
|
|
2150
|
+
("POST", _) if !machine => status(
|
|
2151
|
+
401,
|
|
2152
|
+
br#"{"error":{"code":"worker.unauthorized","message":"m"}}"#,
|
|
2153
|
+
),
|
|
2154
|
+
("POST", "/v1/tensorfs/closure") => ok_json(&closure_value(&checkpoint_for, &base)),
|
|
2155
|
+
("POST", "/v1/tensorfs/presign") => ok_json(&presign_value(&request.body, &base)),
|
|
2156
|
+
("GET", path) => match checkpoint_for.bodies.get(&path["/obj/".len()..]) {
|
|
2157
|
+
Some(body) => status(200, body),
|
|
2158
|
+
None => status(404, b"absent"),
|
|
2159
|
+
},
|
|
2160
|
+
_ => status(404, b"no route"),
|
|
2161
|
+
}
|
|
2162
|
+
});
|
|
2163
|
+
let origin = origin(dispatch);
|
|
2164
|
+
*base_slot.lock().unwrap() = origin.base.clone();
|
|
2165
|
+
let policy = SourcePolicy::default();
|
|
2166
|
+
let credential =
|
|
2167
|
+
credential_from_spec("worker om-machine worker-token", vec!["127.0.0.1".into()]).unwrap();
|
|
2168
|
+
let mut request = PullRequest::new(&store, &origin.base, "acme/model", &credential, &policy);
|
|
2169
|
+
request.sample_seconds = 0.025;
|
|
2170
|
+
pull(&request).unwrap();
|
|
2171
|
+
let anonymous_root = temporary("worker-cred-anon");
|
|
2172
|
+
let anonymous = Store::init(&anonymous_root).unwrap();
|
|
2173
|
+
let mut refused = PullRequest::new(&anonymous, &origin.base, "acme/model", &Anonymous, &policy);
|
|
2174
|
+
refused.sample_seconds = 0.025;
|
|
2175
|
+
assert!(pull(&refused)
|
|
2176
|
+
.unwrap_err()
|
|
2177
|
+
.detail
|
|
2178
|
+
.contains("worker.unauthorized"));
|
|
2179
|
+
for spec in ["worker om-machine", "worker a b c", "machine a b"] {
|
|
2180
|
+
let refusal = credential_from_spec(spec, vec![]).err().unwrap();
|
|
2181
|
+
assert_eq!(refusal.code, Code::CREDENTIAL_REQUIRED, "{spec}");
|
|
2182
|
+
}
|
|
2183
|
+
let _ = std::fs::remove_dir_all(root);
|
|
2184
|
+
let _ = std::fs::remove_dir_all(anonymous_root);
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2137
2187
|
// ---------------------------------------------------------------- the predicate
|
|
2138
2188
|
|
|
2139
2189
|
#[test]
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
//! A hub whose certificate this machine does not trust is a verdict, not weather: `tfs fetch`
|
|
2
|
+
//! refuses it typed on the first handshake, and `--ca-file` names the private CA that makes
|
|
3
|
+
//! the same hub reachable.
|
|
4
|
+
|
|
5
|
+
use std::io::{Read, Write};
|
|
6
|
+
use std::net::{SocketAddr, TcpListener, TcpStream};
|
|
7
|
+
use std::process::Command;
|
|
8
|
+
use std::sync::{mpsc, Arc};
|
|
9
|
+
|
|
10
|
+
const ENVELOPE: &str =
|
|
11
|
+
r#"{"error":{"code":"checkpoint_not_found","message":"no such checkpoint"}}"#;
|
|
12
|
+
|
|
13
|
+
/// A loopback hub under a self-signed authority that answers every call it can read with a
|
|
14
|
+
/// typed 404. Every accepted peer is reported before its handshake.
|
|
15
|
+
fn private_hub() -> (u16, String, mpsc::Receiver<SocketAddr>) {
|
|
16
|
+
let key = rcgen::generate_simple_self_signed(vec!["127.0.0.1".into()]).unwrap();
|
|
17
|
+
let cert = rustls::pki_types::CertificateDer::from(key.cert.der().to_vec());
|
|
18
|
+
let private = rustls::pki_types::PrivateKeyDer::try_from(key.key_pair.serialize_der())
|
|
19
|
+
.unwrap()
|
|
20
|
+
.clone_key();
|
|
21
|
+
let config = rustls::ServerConfig::builder_with_provider(Arc::new(
|
|
22
|
+
rustls::crypto::ring::default_provider(),
|
|
23
|
+
))
|
|
24
|
+
.with_safe_default_protocol_versions()
|
|
25
|
+
.unwrap()
|
|
26
|
+
.with_no_client_auth()
|
|
27
|
+
.with_single_cert(vec![cert], private)
|
|
28
|
+
.unwrap();
|
|
29
|
+
let config = Arc::new(config);
|
|
30
|
+
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
|
31
|
+
let port = listener.local_addr().unwrap().port();
|
|
32
|
+
let (peers, accepted) = mpsc::channel();
|
|
33
|
+
std::thread::spawn(move || {
|
|
34
|
+
for socket in listener.incoming() {
|
|
35
|
+
let Ok(socket) = socket else { return };
|
|
36
|
+
let _ = peers.send(socket.peer_addr().unwrap());
|
|
37
|
+
let conn = rustls::ServerConnection::new(Arc::clone(&config)).unwrap();
|
|
38
|
+
let mut stream = rustls::StreamOwned::new(conn, socket);
|
|
39
|
+
let mut head = Vec::new();
|
|
40
|
+
let mut chunk = [0u8; 4096];
|
|
41
|
+
while !head.windows(4).any(|w| w == b"\r\n\r\n") {
|
|
42
|
+
match stream.read(&mut chunk) {
|
|
43
|
+
Ok(n) if n > 0 => head.extend_from_slice(&chunk[..n]),
|
|
44
|
+
_ => break,
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if head.windows(4).any(|w| w == b"\r\n\r\n") {
|
|
48
|
+
let answer = format!(
|
|
49
|
+
"HTTP/1.1 404 Not Found\r\ncontent-type: application/json\r\ncontent-length: {}\r\nconnection: close\r\n\r\n{ENVELOPE}",
|
|
50
|
+
ENVELOPE.len()
|
|
51
|
+
);
|
|
52
|
+
let _ = stream.write_all(answer.as_bytes());
|
|
53
|
+
stream.conn.send_close_notify();
|
|
54
|
+
let _ = stream.flush();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
(port, key.cert.pem(), accepted)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/// How many connections reached the hub before this call: a sentinel connection is accepted
|
|
62
|
+
/// after every one queued ahead of it.
|
|
63
|
+
fn connections(port: u16, accepted: &mpsc::Receiver<SocketAddr>) -> usize {
|
|
64
|
+
let sentinel = TcpStream::connect(("127.0.0.1", port)).unwrap();
|
|
65
|
+
let mine = sentinel.local_addr().unwrap();
|
|
66
|
+
accepted.iter().take_while(|peer| *peer != mine).count()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
fn fetch(root: &std::path::Path, port: u16, extra: &[&str]) -> (bool, String) {
|
|
70
|
+
let out = Command::new(env!("CARGO_BIN_EXE_tfs"))
|
|
71
|
+
.args(["fetch", root.to_str().unwrap(), "proof/model"])
|
|
72
|
+
.args(["--hub", &format!("https://127.0.0.1:{port}")])
|
|
73
|
+
.args(extra)
|
|
74
|
+
.env("TFS_CREDENTIAL", "")
|
|
75
|
+
.output()
|
|
76
|
+
.unwrap();
|
|
77
|
+
(
|
|
78
|
+
out.status.success(),
|
|
79
|
+
String::from_utf8_lossy(&out.stderr).into_owned(),
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
#[test]
|
|
84
|
+
fn an_untrusted_hub_is_refused_once_and_a_named_ca_reaches_it() {
|
|
85
|
+
let dir = std::env::temp_dir().join(format!("tfs-hub-tls-{}", std::process::id()));
|
|
86
|
+
let _ = std::fs::remove_dir_all(&dir);
|
|
87
|
+
std::fs::create_dir_all(&dir).unwrap();
|
|
88
|
+
let root = dir.join("store");
|
|
89
|
+
let init = Command::new(env!("CARGO_BIN_EXE_tfs"))
|
|
90
|
+
.args(["store", "init", root.to_str().unwrap()])
|
|
91
|
+
.output()
|
|
92
|
+
.unwrap();
|
|
93
|
+
assert!(
|
|
94
|
+
init.status.success(),
|
|
95
|
+
"{}",
|
|
96
|
+
String::from_utf8_lossy(&init.stderr)
|
|
97
|
+
);
|
|
98
|
+
let (port, pem, accepted) = private_hub();
|
|
99
|
+
|
|
100
|
+
let (ok, stderr) = fetch(&root, port, &[]);
|
|
101
|
+
assert!(
|
|
102
|
+
!ok && stderr.contains("REFUSED TLS_UNTRUSTED") && stderr.contains("127.0.0.1"),
|
|
103
|
+
"{stderr}"
|
|
104
|
+
);
|
|
105
|
+
assert_eq!(
|
|
106
|
+
connections(port, &accepted),
|
|
107
|
+
1,
|
|
108
|
+
"an untrusted hub was asked again: {stderr}"
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
let ca = dir.join("hub-ca.pem");
|
|
112
|
+
std::fs::write(&ca, pem).unwrap();
|
|
113
|
+
let (ok, stderr) = fetch(&root, port, &["--ca-file", ca.to_str().unwrap()]);
|
|
114
|
+
assert!(
|
|
115
|
+
!ok && stderr.contains("REFUSED REF_NOT_FOUND") && stderr.contains("checkpoint_not_found"),
|
|
116
|
+
"{stderr}"
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
let garbage = dir.join("garbage.pem");
|
|
120
|
+
std::fs::write(&garbage, "not a certificate").unwrap();
|
|
121
|
+
let (ok, stderr) = fetch(&root, port, &["--ca-file", garbage.to_str().unwrap()]);
|
|
122
|
+
assert!(!ok && stderr.contains("REFUSED UNKNOWN_FORMAT"), "{stderr}");
|
|
123
|
+
let _ = std::fs::remove_dir_all(&dir);
|
|
124
|
+
}
|
|
@@ -3590,9 +3590,9 @@ pub fn transfer_streams(wanted: usize) -> usize {
|
|
|
3590
3590
|
/// plan against the real store, the 16-way walk presigning `wanted` as it reaches it, and
|
|
3591
3591
|
/// the completion proof, all in the compiled core.
|
|
3592
3592
|
///
|
|
3593
|
-
/// `credential` is the one spelling (`bearer <token>`,
|
|
3594
|
-
///
|
|
3595
|
-
/// scoped to the hub's host. `timeout` is the caller's deadline or None for none —
|
|
3593
|
+
/// `credential` is the one spelling (`bearer <token>`, `worker <id> <token>` — a machine's
|
|
3594
|
+
/// worker capability, which reads its owner's unpublished checkpoints — or empty for
|
|
3595
|
+
/// anonymous, published only), scoped to the hub's host. `timeout` is the caller's deadline or None for none —
|
|
3596
3596
|
/// nothing below invents a number of seconds. `sample_seconds` is the liveness ledger's
|
|
3597
3597
|
/// RESOLUTION (configuration, never a verdict); leave it defaulted outside tests.
|
|
3598
3598
|
#[pyfunction]
|
|
@@ -278,6 +278,7 @@ class StoreEra(Refusal): ...
|
|
|
278
278
|
class StoreRootAbsent(Refusal): ...
|
|
279
279
|
class SweepSetIncomplete(Refusal): ...
|
|
280
280
|
class TensorSchemaMismatch(Refusal): ...
|
|
281
|
+
class TlsUntrusted(Refusal): ...
|
|
281
282
|
class TotalBytesCap(Refusal): ...
|
|
282
283
|
class TotalRefsCap(Refusal): ...
|
|
283
284
|
class TrailingBytes(Refusal): ...
|
|
@@ -149,6 +149,7 @@ from ._ext import (
|
|
|
149
149
|
StoreRootAbsent,
|
|
150
150
|
SweepSetIncomplete,
|
|
151
151
|
TensorSchemaMismatch,
|
|
152
|
+
TlsUntrusted,
|
|
152
153
|
TotalBytesCap,
|
|
153
154
|
TotalRefsCap,
|
|
154
155
|
TrailingBytes,
|
|
@@ -306,6 +307,7 @@ __all__ = [
|
|
|
306
307
|
"StoreRootAbsent",
|
|
307
308
|
"SweepSetIncomplete",
|
|
308
309
|
"TensorSchemaMismatch",
|
|
310
|
+
"TlsUntrusted",
|
|
309
311
|
"TotalBytesCap",
|
|
310
312
|
"TotalRefsCap",
|
|
311
313
|
"TrailingBytes",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/examples/optional-cache-backfill.md
RENAMED
|
File without changes
|
|
File without changes
|
{tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/examples/resident_conversion_profile.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/fixtures/repo_apply/blobs.jsonl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/fixtures/repo_apply/header.cbor
RENAMED
|
File without changes
|
{tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/fixtures/repo_apply/manifest.json
RENAMED
|
File without changes
|
{tensorfs-0.3.73 → tensorfs-0.3.75}/crates/tensorfs-core/tests/fixtures/repo_apply/mutation.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|