Metadata-Version: 2.4
Name: libcore-hng
Version: 2.0.32
Summary: A core library for scalable Python applications
Author-email: kaioman <kajin0318@gmail.com>
Project-URL: Homepage, https://github.com/kaioman/libcore-hng
Project-URL: Repository, https://github.com/kaioman/libcore-hng
Project-URL: Issues, https://github.com/kaioman/libcore-hng/issues
Description-Content-Type: text/markdown
Requires-Dist: pydantic
Requires-Dist: psutil
Requires-Dist: pandas
Requires-Dist: openpyxl
Requires-Dist: cryptography
Requires-Dist: google-cloud-secret-manager
Requires-Dist: Pillow
Requires-Dist: PyJWT

# libcore-hng

libcore-hng は、設定管理・ロギング・例外処理・暗号化・ファイル操作を共通化するための Python コアライブラリです。Web アプリケーション本体ではなく、他の Python アプリケーションから利用するための基盤として設計されています。さらに、設計ドキュメントや Copilot 向けの指示ファイルを含め、別のプロジェクトでもそのままひな型として再利用しやすい構成にもなっています。

## このライブラリでできること

- 設定ファイルの読み込みと共通化
- ログ出力の統一
- 独自例外の整理
- 設定ファイルの暗号化・復号化
- GCP Secret Manager との連携
- Excel / JSON / ファイル操作の補助

## 利用上の注意

- このリポジトリは共通ライブラリであり、業務ロジックを持つアプリケーション本体ではありません。
- 機密情報は平文でコミットしないでください。暗号化ファイルと Secret Manager を使って管理してください。
- 設定や秘密情報の扱いは、既存の共通基盤を通じて行ってください。
- 実装の詳細や開発ルールは docs 配下を参照してください。
- 設計書・ルール文書・[.github/copilot-instructions.md](.github/copilot-instructions.md) は、他プロジェクトでの雛形としても活用できます。
- ログのローテーションは `TimedRotatingFileHandler` ベースで、既定設定で `when="midnight"`、`interval=1` により日次で切り替わる構成です。
- アーカイブ済ログファイルの保持件数は `log_backupCount` により制御され、古いログは `doRollover()` 実行時に削除対象として扱われます。

## 参考ドキュメント

- [docs/architecture.md](docs/architecture.md)
- [docs/business_rules.md](docs/business_rules.md)
- [docs/architecture_rules.md](docs/architecture_rules.md)
- [docs/coding_rules.md](docs/coding_rules.md)
- [docs/directory_rules.md](docs/directory_rules.md)
- [docs/naming_rules.md](docs/naming_rules.md)
- [docs/testing_rules.md](docs/testing_rules.md)

## アプリ初期処理サンプル

このプロジェクトでは、`AppInitializer` を用いてアプリケーションの初期化処理を行います。
共通の初期化は `libcore_hng.utils.app_core.init_app()` で行い、アプリごとの設定型はアプリ側で拡張します。
また、アプリ固有の起動モジュール `app_init.py`(アプリごとに作成)で `config` をモジュールグローバルとして公開することで別ファイルからも拡張設定を型付きで参照できます。
バージョン2.0.27以前との互換性を保つため、 `app.core.config` への参照も継続して利用できます
---

### アプリ初期化方法

アプリごとの起動モジュール例
OverrideConfigクラスは拡張設定クラスの例(拡張設定クラスはBaseConfigを継承して作成する)

```python
import libcore_hng.utils.app_core as app
from libcore_hng.core.base_config import BaseConfig
from libcore_hng.configs.logger import LoggerConfig

class ExtendedLoggerConfig(LoggerConfig):
    ext1: str = "default"

class OverrideConfig(BaseConfig):
    logging: ExtendedLoggerConfig = ExtendedLoggerConfig()

# 設定クラス定義
CONFIG_CLS = OverrideConfig

def init_app(base_file: str, *config_file: str) -> CONFIG_CLS:
    """
    アプリケーションの初期化処理を実行する

    Parameters
    ----------
    base_file : str
        基準となるファイルパス (デフォルト: __file__)
    *config_file : str, optional
        ロガー設定ファイル名やその他設定ファイル
        BaseConfig.load_config にそのまま渡されるため、複数指定可能
    
    Returns
    -------
    CONFIG_CLS
        ロードされた設定インスタンス
    """
    global config
    app.init_app(CONFIG_CLS, base_file, *config_file)
    config = app.get_config(CONFIG_CLS)
    return config

# アプリ初期化処理(import時に1度だけ実行される)
config: CONFIG_CLS = init_app(__file__, "app_config.json", "app_config_ext.json")

```

起動モジュールの呼び出し例(app_initは起動モジュール名)

```python
from app_init import config

print(config.logging.ext1)
print(config.logging.log_method_end_emoji)

```

---

### 設定ファイルの暗号化と復号鍵の管理

機密情報を含む設定ファイルを保護するため、ファイルを暗号化し、その復号鍵を Google Cloud Secret Manager に安全に保存して管理します。開発環境と本番環境で同じ仕組みを使用することで、セキュアで統一された運用が可能です。詳細な運用方針は [docs/business_rules.md](docs/business_rules.md) を参照してください。

#### 手順

1. **設定ファイルの暗号化**: `libcore_hng.utils.crypto.create_encryption_file` を使用して、既存のJSONファイルを暗号化します。これにより、元のファイル名に `.enc` が付いた暗号化ファイルが生成され、標準出力に復号鍵が表示されます。
2. **復号鍵の登録**: コンソールに表示された鍵をコピーし、GCP Secret Manager に登録します（例: `my-app-secret-dev`, `my-app-secret-prod`）。

#### 実装例 (`tests/test_016_enc_file.py`)

```python
import libcore_hng.utils.app_core as app
import libcore_hng.utils.crypto as crypto
from libcore_hng.core.base_config import BaseConfig

# アプリ初期化
app.init_app(BaseConfig, __file__, "logger.json")

# 設定ファイルを暗号化して新規ファイル (.enc) として作成
# 戻り値として復号鍵が得られます
key = crypto.create_encryption_file("configs/test-config.json")

# 生成された鍵を表示
print("以下の鍵を GCP Secret Manager に登録してください:")
print(key.decode("utf-8"))
```

`BaseConfig.load_config` は拡張子が `.enc` のファイルを自動的に検知し、暗号化ファイルとして復号・ロードする機能を備えています。実装上の詳細や制約は [docs/architecture.md](docs/architecture.md) と [docs/architecture_rules.md](docs/architecture_rules.md) を参照してください。

復号に必要なGCP設定は、以下の環境変数、または`app_config.json`で設定された値から自動的に取得されます。

- `GCP_PROJECT_ID`: GCPのプロジェクトID。WIF無効時に使用。
- `GCP_SECRET_NAME`: GCP Secret Manager に登録したシークレットのベース名。WIF無効時に使用。
- `APP_ENV`: 環境名（例: `dev`, `prod`）。シークレット名のサフィックスとして使用されます（デフォルト: `dev`）。

### GCP Workload Identity Federation (WIF) を利用した鍵の取得

`libcore-hng` は、GCP Workload Identity Federation (WIF) を利用して Google Secret Manager から復号鍵を安全に取得する機能をサポートしています。これにより、CI/CD環境や異なるクラウドプロバイダーなど、GCP外の環境から直接サービスアカウントキーを配布することなく、GCPリソースにセキュアにアクセスできます。

#### 仕組み

`secret_manager.py` 内の `_get_secret_with_wif` 関数がこのプロセスを管理します。主な流れは以下の通りです。

1. **自前JWT (Subject Token) の生成**: `libcore-hng` は、設定された発行者 (`issuer`) と秘密鍵 (`WIF_PRIVATE_KEY_PATH` 環境変数またはデフォルトパスから取得) を使用して、自身の認証情報を示す JWT を生成します。この JWT は、WIF プールとプロバイダーをオーディエンスとして指定します。
2. **Google STS (Security Token Service) との連携**: 生成された自前 JWT は、Google STS エンドポイントに送信されます。STS はこの JWT を検証し、GCP が信頼する一時的なフェデレーテッドトークンに交換します。
3. **サービスアカウントの偽装 (Impersonation)**: フェデレーテッドトークンを使用して、指定されたサービスアカウント (`service_account_email`) を偽装するためのアクセスキーを IAM Credentials API から取得します。これにより、`libcore-hng` はそのサービスアカウントが持つ権限で GCP リソースにアクセスできるようになります。
4. **Secret Manager からシークレットを取得**: サービスアカウントとして取得した最終的なアクセスキーを用いて、Google Secret Manager クライアントを初期化し、指定されたシークレット (`secret_name` と `app_env` から構成される) から復号鍵を取得します。

#### 必要な設定

WIF を利用するには、`app_config.json` の `gcp` セクションで以下の設定を行うか、対応する環境変数を設定する必要があります。

- `wif_enabled`: `true` に設定して WIF を有効にします。
- `project_number`: Workload Identity Pool が属する GCP プロジェクトの番号。
- `pool_id`: Workload Identity Pool の ID。
- `provider_id`: Workload Identity Provider の ID。
- `service_account_email`: 偽装する GCP サービスアカウントのメールアドレス。
- `issuer`: 自前 JWT の発行者。通常は WIF プロバイダーの設定と一致させます。
- `kid`: 自前 JWT の署名に使用するキーID。
- `sts_url`: Security Token Service (STS) のエンドポイントURL。デフォルト値が設定されています。
- `iam_credentials_url_base`: IAM Credentials API のベースURL。デフォルト値が設定されています。

また、自前 JWT の署名に使用する秘密鍵のパスを環境変数 `WIF_PRIVATE_KEY_PATH` で指定する必要があります（例: `/path/to/your/private_key.pem`）。指定がない場合は、デフォルトで `~/.ssh/uw_private_key.pem` が使用されます。

※ 例: `GCP_SECRET_NAME=my-app-secret`, `APP_ENV=prod` の場合、GCPから `my-app-secret-prod` のシークレットを取得します。WIF を使用する場合、`GCP_PROJECT_ID` と `GCP_SECRET_NAME` は WIF 無効時のフォールバックとしてのみ機能します。

---

### 環境変数設定例（Docker/ローカル開発）

環境変数を使用して、GCP Secret Manager へのアクセス情報、WIF 関連の設定、またはCI/CD・ローカル用の一時的な復号鍵を直接渡すことができます。`app_config.json` での設定値よりも環境変数が優先されます。

`docker-compose.yml` での設定例を以下に示します。

```yaml
services:
  app:
    image: your-app-image
    environment:
      # --- GCP Workload Identity Federation (WIF) を利用する場合 ---
      - WIF_ENABLED=true
      - GCP_PROJECT_NUMBER=${GCP_PROJECT_NUMBER}
      - GCP_POOL_ID=${GCP_POOL_ID}
      - GCP_PROVIDER_ID=${GCP_PROVIDER_ID}
      - GCP_SERVICE_ACCOUNT_EMAIL=${GCP_SERVICE_ACCOUNT_EMAIL}
      - GCP_ISSUER=${GCP_ISSUER}
      - GCP_KID=${GCP_KID}
      - WIF_PRIVATE_KEY_PATH=/path/to/your/private_key.pem
      - APP_ENV=prod  # 開発時は dev などを指定

      # --- または、従来の GCP Secret Manager 連携 (WIF無効時) ---
      # WIF_ENABLED を false にするか、未設定の場合に適用されます。
      - GCP_PROJECT_ID=${GCP_PROJECT_ID}
      - GCP_SECRET_NAME=${GCP_SECRET_NAME}
      # - APP_ENV=prod は WIF の場合と共通
      
      # --- または、復号鍵を直接指定する場合 (GCP設定より優先されます) ---
      - APP_SECRET_KEY=${APP_SECRET_KEY}
```

※ 開発時やデプロイ時には、Docker Composeが読み込む `.env` ファイルなどにこれらの変数を記述しておくことで、安全に鍵情報や設定をコンテナへ渡すことができます。

---

### 他プロジェクトでも再利用しやすい構成

このリポジトリでは、実装本体だけでなく、設計書・ルール文書・Copilot 向けの指示ファイルを一緒に管理しています。これらは、別の Python プロジェクトで同じような構成を作る際の参考実装やひな型として利用できます。

特に、以下のファイル群は再利用を意識した構成です。

- [docs/architecture.md](docs/architecture.md)
- [docs/business_rules.md](docs/business_rules.md)
- [docs/architecture_rules.md](docs/architecture_rules.md)
- [docs/coding_rules.md](docs/coding_rules.md)
- [docs/directory_rules.md](docs/directory_rules.md)
- [docs/naming_rules.md](docs/naming_rules.md)
- [docs/testing_rules.md](docs/testing_rules.md)
- [.github/copilot-instructions.md](.github/copilot-instructions.md)
