Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
48e8fc4
Add AWS S3 SigV4 region CI tests
tishin-endou May 28, 2026
1b8e51f
fix(ci): separate S3 credentials and mask artifacts
tishin-endou Jun 13, 2026
0e83912
feat(s3): Amazon S3機関ストレージのE2Eテストノートブックを追加
tishin-endou Jul 20, 2026
25c5fa7
ci(s3): AWS S3リージョンテストを既定で無効化(パブリックリポジトリ対応)
tishin-endou Jul 21, 2026
0e03aed
Merge upstream/main into feature/aws-s3-sigv4
tishin-endou Jul 21, 2026
064bf08
test(s3): SigV4回帰試験ノートブックとエラーコード採取スクリプトを追加
tishin-endou Sep 25, 2026
1b4ea23
test(s3): SigV4回帰ノートブックにS-7チャンクアップロードを追加
tishin-endou Sep 25, 2026
fd41870
test(s3): S-7を200MBに変更しS-6に認証系3ケースを追加
tishin-endou Sep 25, 2026
7e08e3c
test(s3): let .config.yaml supply the RDM URLs for the SigV4 notebook
tishin-endou Sep 27, 2026
139eac6
test(s3): create and delete the SigV4 test buckets inside the notebook
tishin-endou Sep 27, 2026
0eb574e
Fix failure-artifact capture in run_pw / _finish_pw_context
tishin-endou Oct 1, 2026
d966ac7
test(s3): ログイン・アドオン接続・証跡レコーダを実機の挙動に合わせる
tishin-endou Oct 1, 2026
718cf5e
test(s3): バケット生成の入口を整理し、資格情報の切り分けを先に行う
tishin-endou Oct 1, 2026
69ffb10
test(s3): G-10 の判定をファイル一覧のツールバーのダウンロードに変える
tishin-endou Oct 1, 2026
49541b5
test(s3): S-3 でフォルダの遅延読み込みが走らない問題を直す
tishin-endou Oct 1, 2026
fc0211b
test(s3): S-5 の copy/move 判定を要求本文と行 notify で行う
tishin-endou Oct 1, 2026
70a065e
test(s3): 機関ストレージの保存を submit ハンドラが付いてから押す
tishin-endou Oct 1, 2026
c2ddf95
test(s3): finish the SigV4 notebook after the staging2 run
tishin-endou Oct 1, 2026
18899f2
test(s3): make the SigV4 notebook publishable
tishin-endou Oct 1, 2026
8af4e13
test(s3): add a cleanup script for the SigV4 regression run
tishin-endou Oct 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 64 additions & 2 deletions .github/scripts/generate_ci_config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ set -xeuo pipefail

if [[ $# -lt 2 ]]; then
cat >&2 <<'USAGE'
Usage: generate_ci_config.sh <output_path> <base_config_yaml> [--minio] [--jupyterhub] [--weko] [--flowable] [--s3compatsigv4] [--s3compatsigv4-inst] [--wiki]
Usage: generate_ci_config.sh <output_path> <base_config_yaml> [--minio] [--aws-s3] [--jupyterhub] [--weko] [--flowable] [--s3compatsigv4] [--s3compatsigv4-inst] [--wiki]
USAGE
exit 1
fi
Expand All @@ -12,6 +12,7 @@ OUTPUT=$1
BASE_CONFIG=$2
shift 2
MINIO=false
AWS_S3=false
JUPYTERHUB=false
WEKO=false
FLOWABLE=false
Expand All @@ -24,6 +25,9 @@ for arg in "$@"; do
--minio)
MINIO=true
;;
--aws-s3)
AWS_S3=true
;;
--jupyterhub)
JUPYTERHUB=true
;;
Expand All @@ -50,6 +54,11 @@ for arg in "$@"; do

done

if [[ "${MINIO}" == "true" && "${AWS_S3}" == "true" ]]; then
echo "--minio and --aws-s3 both write storages_s3 and cannot be used together" >&2
exit 1
fi

cp "${BASE_CONFIG}" "${OUTPUT}"

if [[ "${MINIO}" == "true" ]]; then
Expand Down Expand Up @@ -78,13 +87,66 @@ s3compat_test_bucket_name_2: '${S3COMPAT_BUCKET_NAME_2}'
s3compat_type_name_1: '${S3COMPAT_SERVICE_NAME}'
s3compat_type_name_2: '${S3COMPAT_SERVICE_NAME}'
EOF
else
elif [[ "${AWS_S3}" != "true" ]]; then
cat >> "${OUTPUT}" <<'EOF'

storages_s3: []
EOF
fi

if [[ "${AWS_S3}" == "true" ]]; then
required_aws_s3_vars=(
AWS_S3_ACCESS_KEY_1
AWS_S3_SECRET_KEY_1
AWS_S3_ACCESS_KEY_2
AWS_S3_SECRET_KEY_2
AWS_S3_LEGACY_REGION
AWS_S3_LEGACY_BUCKET_NAME
AWS_S3_V4_REGION
AWS_S3_V4_BUCKET_NAME
)

missing_aws_s3_vars=()
for var_name in "${required_aws_s3_vars[@]}"; do
if [[ -z "${!var_name:-}" ]]; then
missing_aws_s3_vars+=("${var_name}")
fi
done

if [[ ${#missing_aws_s3_vars[@]} -gt 0 ]]; then
echo "AWS S3 test credentials are not set: ${missing_aws_s3_vars[*]}" >&2
exit 1
fi

if [[ "${AWS_S3_ACCESS_KEY_1}" == "${AWS_S3_ACCESS_KEY_2}" ]]; then
echo "AWS_S3_ACCESS_KEY_1 and AWS_S3_ACCESS_KEY_2 must be different" >&2
exit 1
fi

if [[ "${AWS_S3_SECRET_KEY_1}" == "${AWS_S3_SECRET_KEY_2}" ]]; then
echo "AWS_S3_SECRET_KEY_1 and AWS_S3_SECRET_KEY_2 must be different" >&2
exit 1
fi

cat >> "${OUTPUT}" <<EOF

storages_s3:
- id: 's3'
name: 'Amazon S3'
skip_too_many_files_check: true

s3_access_key_1: '${AWS_S3_ACCESS_KEY_1}'
s3_secret_access_key_1: '${AWS_S3_SECRET_KEY_1}'
s3_default_region_1: '${AWS_S3_LEGACY_REGION}'
s3_test_bucket_name_1: '${AWS_S3_LEGACY_BUCKET_NAME}'

s3_access_key_2: '${AWS_S3_ACCESS_KEY_2}'
s3_secret_access_key_2: '${AWS_S3_SECRET_KEY_2}'
s3_default_region_2: '${AWS_S3_V4_REGION}'
s3_test_bucket_name_2: '${AWS_S3_V4_BUCKET_NAME}'
EOF
fi

if [[ "${JUPYTERHUB}" == "true" ]]; then
if [[ -z "${TLJH_URL:-}" || -z "${TLJH_USERNAME:-}" || -z "${TLJH_PASSWORD:-}" ]]; then
echo "TLJH connection information is not set" >&2
Expand Down
91 changes: 91 additions & 0 deletions .github/scripts/mask_sensitive_artifacts.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/bin/bash
set -euo pipefail

if [[ $# -lt 1 ]]; then
echo "Usage: $0 <artifact-dir> [<artifact-dir> ...]" >&2
exit 1
fi

base_dir=$(pwd)

mask_value() {
local value="$1"
local length=${#value}
if (( length <= 8 )); then
printf '****'
return
fi

local prefix="${value:0:4}"
local suffix="${value: -4}"
local mask_length=$((length - 8))
local stars
stars=$(printf '%*s' "$mask_length" '' | tr ' ' '*')
printf '%s%s%s' "$prefix" "$stars" "$suffix"
}

replace_in_file() {
local file="$1"
local value="$2"
local masked="$3"

VALUE="$value" MASKED="$masked" perl -0pi -e 's/\Q$ENV{VALUE}\E/$ENV{MASKED}/g' "$file"
}

replace_in_tree() {
local target_dir="$1"
local value="$2"
local masked="$3"

find "$target_dir" -type f \
\( -name '*.ipynb' -o -name '*.log' -o -name '*.json' -o -name '*.har' -o -name '*.html' -o -name '*.js' -o -name '*.txt' -o -name '*.yaml' -o -name '*.yml' \) \
-print0 |
while IFS= read -r -d '' file; do
replace_in_file "$file" "$value" "$masked"
done

find "$target_dir" -type f -name 'har.zip' -print0 |
while IFS= read -r -d '' zip_file; do
local tmp_dir
local output_zip
tmp_dir=$(mktemp -d)
case "$zip_file" in
/*)
output_zip="$zip_file"
;;
*)
output_zip="$base_dir/$zip_file"
;;
esac
unzip -q "$zip_file" -d "$tmp_dir"
find "$tmp_dir" -type f -print0 |
while IFS= read -r -d '' file; do
replace_in_file "$file" "$value" "$masked"
done
(cd "$tmp_dir" && zip -qr "$output_zip" .)
rm -rf "$tmp_dir"
done
}

while IFS='=' read -r name value; do
case "$name" in
*ACCESS_KEY*|*SECRET_KEY*|*PASSWORD*|*TOKEN*)
;;
*)
continue
;;
esac

if [[ -z "$value" || ${#value} -lt 8 ]]; then
continue
fi

masked=$(mask_value "$value")
echo "::add-mask::$value"

for target_dir in "$@"; do
if [[ -d "$target_dir" ]]; then
replace_in_tree "$target_dir" "$value" "$masked"
fi
done
done < <(env)
64 changes: 64 additions & 0 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,30 @@ jobs:
jupyterhub_enabled: false
flowable_enabled: false
wiki_enabled: false
# AWS S3 (SigV4リージョン) の実接続テスト。
# このジョブは実AWSのアクセスキー等を GitHub Secrets
# (AWS_S3_ACCESS_KEY_1/2, AWS_S3_SECRET_KEY_1/2,
# AWS_S3_LEGACY_REGION, AWS_S3_LEGACY_BUCKET_NAME,
# AWS_S3_V4_REGION, AWS_S3_V4_BUCKET_NAME)
# から取得する。パブリックリポジトリでは Secret を登録できないため
# 既定では無効化している(有効なままだと認証情報未設定でCIが失敗する)。
#
# ローカル / Secret を設定済みのプライベートfork でテストする場合のみ、
# 以下のブロックのコメントを解除して有効化すること。
# - name: user-aws-s3
# display_name: "User Tests (AWS S3 SigV4 Regions)"
# include_admin: false
# skip_admin: true
# skip_metadata: true
# skip_default_storage: true
# skip_login: true
# skip_130mb_upload: true
# minio_enabled: false
# aws_s3_enabled: true
# weko_enabled: false
# jupyterhub_enabled: false
# flowable_enabled: false
# wiki_enabled: false
- name: admin-minio
display_name: "Admin Tests (MinIO)"
include_admin: true
Expand Down Expand Up @@ -346,6 +370,7 @@ jobs:
name: E2E ${{ matrix.test-group.display_name }}
env:
MINIO_ENABLED: ${{ matrix.test-group.minio_enabled == true && 'true' || 'false' }}
AWS_S3_ENABLED: ${{ matrix.test-group.aws_s3_enabled == true && 'true' || 'false' }}
S3COMPATSIGV4_ENABLED: ${{ matrix.test-group.s3compatsigv4_enabled == true && 'true' || 'false' }}
S3COMPATSIGV4_INST_ENABLED: ${{ matrix.test-group.s3compatsigv4_institutional_storage == true && 'true' || 'false' }}
WEKO_ENABLED: ${{ matrix.test-group.weko_enabled == true && 'true' || 'false' }}
Expand All @@ -358,6 +383,14 @@ jobs:
MINIO_ENDPOINT: http://minio:9000
MINIO_REGION: us-east-1
MINIO_SERVICE_NAME: MinIO (CI)
AWS_S3_ACCESS_KEY_1: ${{ matrix.test-group.aws_s3_enabled == true && secrets.AWS_S3_ACCESS_KEY_1 || '' }}
AWS_S3_SECRET_KEY_1: ${{ matrix.test-group.aws_s3_enabled == true && secrets.AWS_S3_SECRET_KEY_1 || '' }}
AWS_S3_ACCESS_KEY_2: ${{ matrix.test-group.aws_s3_enabled == true && secrets.AWS_S3_ACCESS_KEY_2 || '' }}
AWS_S3_SECRET_KEY_2: ${{ matrix.test-group.aws_s3_enabled == true && secrets.AWS_S3_SECRET_KEY_2 || '' }}
AWS_S3_LEGACY_REGION: ${{ matrix.test-group.aws_s3_enabled == true && secrets.AWS_S3_LEGACY_REGION || '' }}
AWS_S3_LEGACY_BUCKET_NAME: ${{ matrix.test-group.aws_s3_enabled == true && secrets.AWS_S3_LEGACY_BUCKET_NAME || '' }}
AWS_S3_V4_REGION: ${{ matrix.test-group.aws_s3_enabled == true && secrets.AWS_S3_V4_REGION || '' }}
AWS_S3_V4_BUCKET_NAME: ${{ matrix.test-group.aws_s3_enabled == true && secrets.AWS_S3_V4_BUCKET_NAME || '' }}

steps:
- name: Checkout test repository
Expand Down Expand Up @@ -1280,6 +1313,28 @@ jobs:
docker-compose exec -T web python3 -m scripts.register_erad_metadata /tmp/erad_sample.csv
echo "e-Rad data registered successfully"

- name: Validate and mask sensitive test credentials
working-directory: e2e-tests
run: |
set -euo pipefail

bash .github/scripts/mask_sensitive_artifacts.sh /tmp/nonexistent-mask-target

if [ "${AWS_S3_ENABLED}" = "true" ]; then
if [ -z "${AWS_S3_ACCESS_KEY_1}" ] || [ -z "${AWS_S3_SECRET_KEY_1}" ] || [ -z "${AWS_S3_ACCESS_KEY_2}" ] || [ -z "${AWS_S3_SECRET_KEY_2}" ]; then
echo "AWS S3 test credentials are not fully configured. Set AWS_S3_ACCESS_KEY_1, AWS_S3_SECRET_KEY_1, AWS_S3_ACCESS_KEY_2, and AWS_S3_SECRET_KEY_2 secrets."
exit 1
fi
if [ "${AWS_S3_ACCESS_KEY_1}" = "${AWS_S3_ACCESS_KEY_2}" ]; then
echo "AWS_S3_ACCESS_KEY_1 and AWS_S3_ACCESS_KEY_2 must be different."
exit 1
fi
if [ "${AWS_S3_SECRET_KEY_1}" = "${AWS_S3_SECRET_KEY_2}" ]; then
echo "AWS_S3_SECRET_KEY_1 and AWS_S3_SECRET_KEY_2 must be different."
exit 1
fi
fi

- name: Prepare test configuration
working-directory: e2e-tests
run: |
Expand Down Expand Up @@ -1337,6 +1392,9 @@ jobs:
if [ "${MINIO_ENABLED}" = "true" ]; then
args+=(--minio)
fi
if [ "${AWS_S3_ENABLED}" = "true" ]; then
args+=(--aws-s3)
fi
if [ "${JUPYTERHUB_ENABLED}" = "true" ]; then
args+=(--jupyterhub)
fi
Expand Down Expand Up @@ -1414,6 +1472,12 @@ jobs:
echo "ticket=$TICKET" >> $GITHUB_OUTPUT
echo "Extracted ticket: $TICKET"

- name: Mask sensitive values in test artifacts
if: always()
working-directory: e2e-tests
run: |
bash .github/scripts/mask_sensitive_artifacts.sh result result-failed

- name: Generate Excel summary
if: always()
working-directory: e2e-tests
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,16 @@ venv/
*~
.DS_Store

# Claude Code / Claude in Cowork local settings (machine-specific, not for repo)
.claude/

# Test outputs and reports
*.log
*.har
last-screenshots/
test-results/
reports/
evidence/

# Config files with secrets
*.config.yaml
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,14 @@ GRDMには、一般的なGUI操作を行うためのユーティリティ関数

全てのテスト手順Jupyter Notebookの実行結果には、動画でのスクリーンキャプチャを添付することで、状況の確認の助けとします。動画のシーンがテストのどの手順に対応しているかの参考にできるよう、実行中のセルの見出し文字列が字幕として挿入されます。

## Amazon S3 SigV4 回帰試験

`テスト手順-管理者機能-S3-機関ストレージ-SigV4回帰.ipynb` は、WaterButler の Amazon S3 プロバイダを SigV4 化した際の回帰試験 (S-0〜S-7) を実施するテスト手順 Notebook です。既存の `テスト手順-管理者機能-S3-機関ストレージ.ipynb` とは別ファイルとして管理し、機関ストレージ登録・大量ファイル一覧・バージョニング削除・サーバ側コピー/移動を確認します。
試験に使う S3 バケット 3 つ (通常 / バージョニング有効 / ap-northeast-1) は、**既定では Notebook が実行時に生成し、後始末で削除します**。名前は `{bucket_prefix}-{bucket_suffix}-{std,ver,apne1}` (既定 `e2e-sigv4-<YYYYmmdd-HHMMSS>-<4桁乱数>-…`) で、生成セルが `S-0-buckets.json` に記録します。既存のバケットを使う場合は `.config.yaml` に `s3_bucket` / `s3_bucket_versioned` / `s3_bucket_apne1` の 3 つを書いてください。指定したバケットは本試験が置いた残骸だけを消し、バケット自体は削除しません。`s3:CreateBucket` / `s3:PutBucketVersioning` / `s3:DeleteBucket` を含む IAM 権限が必要です (不足時は生成セルが必要な権限一覧を表示して停止します)。

`scripts/s3_complete_error_codes.py` は、CompleteMultipartUpload が AWS S3 から返すエラーコードを採取して WaterButler の判定表と突き合わせる単体スクリプトです (Notebook の S-6 に対応)。`--dry-run` で実行計画のみを表示できます。認証情報は boto3 の既定の解決順 (環境変数 / `AWS_PROFILE` / インスタンスロール) で解決し、出力には含めません。
対象バケットは `--create-bucket` を付けると `e2e-sigv4-s6-<YYYYmmdd-HHMMSS>` を生成し、**正常終了でも例外でも空にして削除します**。既存のバケットを使う場合は環境変数 `E2E_S3_BUCKET` で指定します。Notebook がバケットを生成する運用では生成セルが出力する `export E2E_S3_BUCKET=…` / `export E2E_S3_REGION=…` の行をそのまま貼って実行します (この場合は Notebook の後始末より前に実行すること)。

## セキュリティと機密情報の管理

このリポジトリをGitで管理・公開する際は、機密情報の流出を防ぐためにpre-commit hookを設定してください。
Expand Down
Loading