Skip to content

env export: S3 dest が '/' 終端のときファイル名が補完されず空キーオブジェクトが作られる #24

Description

@takemi-ohama

概要

devbase env export s3://bucket/prefix/ のように 末尾 / の S3 URI を dest に指定すると、ファイル名が補完されず prefix/ というキー(ファイル名部分が空)のオブジェクトが作成されてしまう。

aws s3 cp の慣習(末尾 / はディレクトリ扱いで元ファイル名を補完)と異なる挙動で、利用者の期待を裏切る。

再現手順

```bash
$ devbase env export s3://nyle-devbase-422746423551-ap-northeast-1-an/env/ohama/
...
S3 へ書き込みました: s3://nyle-devbase-422746423551-ap-northeast-1-an/env/ohama/ (sse=aws:kms)
export 完了: s3://nyle-devbase-422746423551-ap-northeast-1-an/env/ohama/ (6862 bytes)

$ aws s3 ls s3://nyle-devbase-422746423551-ap-northeast-1-an/env/ohama/
2026-05-24 07:45:09 6862 ← キー名が `env/ohama/` (ファイル名なし)
```

一方、フルキーを明示すれば正常:

```bash
$ devbase env export s3://.../env/ohama/devbase-env-20260524-074523.dbenv
export 完了: s3://.../env/ohama/devbase-env-20260524-074523.dbenv (6816 bytes)
```

原因

`lib/devbase/env/io_export.py:165`

```python
dest = opts.dest or _default_dest(opts.force_unencrypted)
```

`opts.dest` が明示指定されると `_default_dest` (`./devbase-env-.dbenv`) は呼ばれない。ローカルパスの場合、ディレクトリへの書き込みは OSError で fail-fast するが、S3 backend は末尾 `/` のキーをそのまま受け入れて空ファイル名のオブジェクトを作成してしまう。

想定される対応

いずれか:

  1. ファイル名を自動補完 (`aws s3 cp` 互換、推奨): dest が `s3://...` かつ末尾 `/` の場合、`devbase-env-.dbenv` を append する。
  2. 明示的にエラー: dest が `/` 終端の S3 URI なら `ExportError("S3 dest にはオブジェクトキー(ファイル名)まで含めてください")` で reject する。

ローカルの `_to_local_path` が dest をディレクトリと判定した場合も同じ判断(補完 or エラー)を適用すると挙動が揃う。

影響範囲

  • 既に空キーオブジェクト(`env/ohama/`, 6862 bytes)が S3 に作られた事例あり → 手動削除済み。
  • 暗号化 SSE は付与されているので機密漏えいリスクは低いが、後続の export で同じキーが上書きされる/import 時に prefix listing が壊れる等の二次被害がありうる。

関連

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions