6 Commits
Author SHA1 Message Date
Simone ScarduzioandClaude Opus 4.7 fefb253924 ci(release): make tag-creation idempotent so locally-pushed tags work (#10)
When the workflow's PAT_TOKEN lacks push-tag permission to this org
repo (the v6.2.0 release hit this), the maintainer can push the
tag locally and re-dispatch the workflow. Previously the "Check if
tag already exists" step errored out fatally; now we fetch tags,
reuse one if present, and only create+push when the tag's missing.

This also lets us recover from a half-completed earlier run without
having to delete the tag and rebuild from scratch.

No behaviour change on a clean run from a writable PAT_TOKEN: the
fetch is a no-op, the rev-parse misses, and the create+push branch
fires exactly as before.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 09:39:35 +02:00
Simone ScarduzioandClaude Opus 4.7 2d345bc663 v6.2.0: deprecate Python deltaglider in favor of deltaglider_proxy (Rust) (#9)
The Rust `deltaglider_proxy` ships proxy + CLI + UI in one binary with a
byte-identical wire format. Maintaining both has been a duplication tax
(metadata-namespace fix v6.1.2 had to land twice). This release is the
final feature release; security/bug fixes stop here.

What this commit does:

- CLI: every invocation prints a deprecation notice to stderr pointing
  at github.com/beshu-tech/deltaglider_proxy with a one-line migration
  alias (`alias dg='deltaglider_proxy s3'`). Banner prints once per
  process; suppress via DG_SUPPRESS_DEPRECATION=1 for CI that hasn't
  migrated yet.
- README: prominent deprecation banner at the top with the migration
  command and the archive-timing notice (~1 week after v6.2.0 ships).
- pyproject.toml: description prefixed with "DEPRECATED" so PyPI search
  results show the warning. Classifier moved Beta -> Inactive.
- CHANGELOG: v6.2.0 entry under "Deprecated" documenting the migration
  path + archive plan, preserving the carried-forward Fixed/Changed/
  Added items from Unreleased.

Repo archive timing: Maintainer will archive ~1 week after v6.2.0 hits
PyPI to give users a window to see the stderr notice on their next
update. PyPI installs continue to work indefinitely.

No behaviour changes to the wire format, the CLI surface, or the
metadata schema. Existing buckets remain readable forever.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 08:57:19 +02:00
Simone ScarduzioandClaude Opus 4.7 d81240be80 fix(metadata): align direct-upload keys to canonical dg-* namespace (#8)
* fix(metadata): align direct-upload keys to canonical dg-* namespace

`_upload_direct` (the path taken by non-delta-eligible files like
.sha1 / .sha512) wrote user-metadata with bare underscored keys
(`original_name`, `file_sha256`, `compression`) while delta and
reference uploads correctly used the canonical dashed namespace
(`dg-original-name`, `dg-file-sha256`, `dg-compression`).

Downstream consumers — most visibly the DeltaGlider Proxy — only
recognised the dashed form, so every .sha1 / .sha512 listing on
a bucket holding deltaglider-uploaded files produced:

    WARN PATHOLOGICAL | Missing/corrupt DG metadata for
    bucket/key.sha1 -- falling back to passthrough.
    Error: Storage error: Missing dg-original-name

This patch aligns the writer to the canonical scheme and keeps the
read path backward-compatible with already-stored bare-keyed objects
via `resolve_metadata`. No re-upload required.

Changes
-------
* `_upload_direct` emits metadata using `f"{METADATA_PREFIX}{key}"`
  (the same pattern delta/reference uploads already use).
* `METADATA_KEY_ALIASES` now lists `compression` and `source_name`
  so `resolve_metadata` works for both fields uniformly.
* Replaced bare `metadata.get("compression")` /
  `metadata.get("original_name")` / `metadata.get("file_size")` /
  `metadata.get("ref_key")` lookups in `DeltaService.get`,
  `DeltaService.delete`, `_delete_delta`, the recursive-delete
  listing path, `client.list_objects_v2`, and
  `client_operations.stats.get_object_info` with `resolve_metadata`
  calls so legacy bare-keyed objects keep working forever.

Tests
-----
* `tests/unit/test_metadata_aliases.py` (new, 11 tests) — pins the
  alias table contract: new dashed keys, legacy bare underscored
  keys, legacy hyphenated keys, priority rule, empty-string
  handling.
* `test_direct_upload_emits_dashed_namespace` in
  `tests/unit/test_core_service.py` — pins the writer to emit only
  dg-* keys.
* Existing tests using the legacy bare `compression: "none"` form
  in `test_s3_compat.py` and `test_recursive_delete_reference_*.py`
  still pass — proving the dual-scheme read contract holds.

Full unit suite: 87/87 pass, mypy clean, ruff clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(metadata): also resolve legacy file_sha256 in get() dispatch

Adversarial review of the original patch caught a second
asymmetry: DeltaService.get's "is this a regular S3 object or
DeltaGlider-managed?" dispatch was a literal-string check
`"dg-file-sha256" not in obj_head.metadata`. After the writer
fix, NEW direct uploads have `dg-file-sha256` so they route
correctly. But ~4400 pre-fix `.sha1` / `.sha512` files in
production have the bare `file_sha256` key, and they were
silently being routed through the "regular S3 object" branch
instead of the "direct upload" branch.

Both branches call `_get_direct` so file content was still
served correctly — but the wrong log message fired
("Downloading regular S3 object (no DeltaGlider metadata)") and
the recorded file-size for telemetry came from obj_head.size
instead of the metadata's `file_size` (same value for direct
uploads, but still semantically wrong).

Swap the literal-string check for `resolve_metadata(meta,
"file_sha256") is None` so both schemes route to the
DeltaGlider-managed branch.

Added regression test `test_get_legacy_direct_upload_not_
misclassified_as_regular_s3` that builds a HEAD response with
the legacy bare-keyed metadata shape (exactly what's stored on
Hetzner today for the .sha files), captures the log messages,
and fails if the "regular S3 object" canary fires.

Demonstrated locally: revert the dispatch back to literal-string
check → new test fails with the canary log line. Restore →
88/88 pass.

CHANGELOG updated to document both fixes (writer + dispatch).

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 10:28:25 +02:00
Simone Scarduzio b6ea6d734a Merge pull request #3 from beshu-tech/optimize-metadata-fetch
Optimize metadata fetch
2025-09-29 23:02:45 +02:00
Simone Scarduzio 09a5899a56 Merge pull request #2 from beshu-tech/fix/intelligent-reference-cleanup
style: Fix linting issues in recursive delete test file
2025-09-29 16:10:58 +02:00
Simone Scarduzio 3074b2cff1 Merge pull request #1 from beshu-tech/feature/boto3-compatible-client
feat: Boto3-compatible client API with enterprise features
2025-09-25 17:23:14 +02:00