Files
content-factory/tasks/020-demo-publishing-s3-assets-compatibility.md

2.9 KiB

Task 020: Demo Publishing S3 Assets Compatibility

Development description: Fix publish dry-run/commit flow so approved assets stored in object storage (s3://...) are correctly bundled for Git publishing in demo Compose mode.

Implementation Details

  • Root cause:
    • Publishing bundle loader accepted only file:// asset URLs.
    • In Compose demo mode, approved assets are stored in MinIO and exposed as s3://bucket/key.
  • Required backend changes:
    • Extend object storage client with read capability (get_bytes).
    • Update publishing asset collector to support both file:// and s3:// sources.
    • Use asset.object_key (or URL-derived key fallback) for object-storage fetch.
    • Preserve existing manifest structure and publish workflow statuses.
  • Validation:
    • Add regression test proving dry-run works when approved assets use s3:// URLs with valid object keys.

Public Interface

  • No API contract changes.
  • Existing endpoints must behave identically, except they no longer fail on s3:// approved assets:
    • POST /api/articles/{article_id}/publishing/dry-run
    • POST /api/articles/{article_id}/publishing/create-commit

Acceptance Criteria

  • Dry-run no longer fails with Approved asset file is unavailable: s3://... when asset object exists.
  • Publish bundle copies approved assets from object storage into target repo workspace.
  • Existing file-based publishing tests continue to pass.
  • New regression test covers s3:// asset URL compatibility.

Verification

  • Run publishing integration suite:
    • PYTHONPATH=/private/tmp/pupline-backend-deps python3 -m unittest apps/backend/tests/integration/test_publishing_git_flow_public_api.py
  • Run task 019 demo smoke:
    • PYTHONPATH=/private/tmp/pupline-backend-deps python3 -m unittest apps/backend/tests/integration/test_end_to_end_demo_stack_smoke_public_api.py
  • Run clean compose checklist manually (down -v -> up --build) and verify publish dry-run/commit steps.

Result

  • Status: Implemented.
  • Files changed:
    • apps/backend/src/infrastructure/object_storage.py
    • apps/backend/src/application/publishing.py
    • apps/backend/tests/integration/test_publishing_git_flow_public_api.py
  • Green evidence:
    • PYTHONPATH=/private/tmp/pupline-backend-deps python3 -m unittest apps/backend/tests/integration/test_publishing_git_flow_public_api.py -> Ran 7 tests ... OK
    • PYTHONPATH=/private/tmp/pupline-backend-deps python3 -m unittest apps/backend/tests/integration/test_end_to_end_demo_stack_smoke_public_api.py -> Ran 1 test ... OK
    • Clean compose check (docker compose down -v -> docker compose up --build -d) + manual public API flow:
      • final approval: 200 PUBLISH_DRY_RUN_REQUIRED
      • publishing dry-run: 201 PUBLISH_COMMIT_READY
      • create-commit: 201 PUBLISH_COMMIT_CREATED
  • Refactor notes:
    • Added storage read path to reuse existing object storage abstractions instead of introducing publish-specific S3 calls.