> For the complete documentation index, see [llms.txt](https://docs.keeper.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.keeper.io/keeperpam/jp/secrets-manager/developer-sdk-library/ruby-sdk.md).

# Ruby SDK

<figure><img src="/files/XAokBMJxqCFiOHcYj3QE" alt="Keeper Secrets Manager Ruby SDK"><figcaption></figcaption></figure>

Keeperシークレットマネージャー (KSM) は、ゼロ知識のシークレット管理プラットフォームです。Ruby SDKを使うと、RubyアプリケーションからKeeperボルトへプログラム経由でアクセスできます。

## 要件

Ruby 3.1以降。

## ダウンロードとインストール

### インストール

詳しくは、[RubyGemsのパッケージページ](https://rubygems.org/gems/keeper_secrets_manager)をご参照ください。

#### gemを使用してインストールする場合

```bash
gem install keeper_secrets_manager -v 17.2.0
```

#### Gemfileに追加する場合

```ruby
gem 'keeper_secrets_manager', '~> 17.2'
```

次に以下を実行します。

```bash
bundle install
```

### ソースコード

Rubyのソースコードは[GitHubリポジトリ](https://github.com/Keeper-Security/secrets-manager/tree/master/sdk/ruby)で公開されています。

## SDKの使用

### ストレージの初期化

SDKでは、クライアントデバイス上にストレージを初期化するためにワンタイムアクセストークンが必要です。初期化後は、SDKが構成を保存し、以降の利用時に使用します。

```ruby
KeeperSecretsManager.new(token: token, config: storage, hostname: hostname, verify_ssl_certs: verify_ssl_certs)
```

| パラメータ              | 型                 | 必須 | デフォルト                  | 説明                                             |
| ------------------ | ----------------- | -- | ---------------------- | ---------------------------------------------- |
| `token`            | `String`          | 任意 | `nil`                  | 初期バインディングに使用するワンタイムアクセストークン                    |
| `config`           | `KeyValueStorage` | 必須 | -                      | 構成を永続化するためのストレージ実装                             |
| `hostname`         | `String`          | 任意 | `'keepersecurity.com'` | APIホスト名 (例: EUデータセンターの場合は 'keepersecurity.eu') |
| `verify_ssl_certs` | `Boolean`         | 任意 | `true`                 | SSL証明書検証の有効/無効の設定                              |

{% hint style="info" %}
ワンタイムアクセストークンを使用する場合、トークンを紐付けて構成を完全に取得するために、少なくとも1回の読み取り操作が必要です。
{% endhint %}

#### 使用例

**ワンタイムアクセストークンを使用する場合:**

```ruby
require 'keeper_secrets_manager'

token = "US:ONE_TIME_TOKEN"

# 初回セットアップ - トークンの紐付け
storage = KeeperSecretsManager::Storage::FileStorage.new('keeper_config.json')
secrets_manager = KeeperSecretsManager.new(token: token, config: storage)

# 紐付けを完了する (少なくとも1回の操作が必要)
records = secrets_manager.get_secrets

# 構成ファイルが保存されたことを確認
File.exist?('keeper_config.json')  # Should return true
```

#### ファイルベースのストレージを使用する場合

アプリケーション再起動後も構成を永続的に保持する場合:

```ruby
require 'keeper_secrets_manager'

# 初回の紐付け後、構成ファイルから読み込む
secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')
```

ボルトで生成されたBase64構成ファイルを使用して接続する場合:

```ruby
require 'keeper_secrets_manager'

base64_config = File.read('config.base64').strip
storage = KeeperSecretsManager::Storage::InMemoryStorage.new(base64_config)
secrets_manager = KeeperSecretsManager.new(config: storage)
```

#### Base64構成文字列を使用する場合

`KeeperSecretsManager.from_config` は、Base64エンコードされた構成文字列向けの便利な初期化メソッドです。コマンダーの `export` コマンドが出力する形式や、`KSM_CONFIG` などの環境変数に保存する形式と同じです。

```ruby
require 'keeper_secrets_manager'

# Base64構成文字列から直接初期化
config_base64 = ENV['KSM_CONFIG']
secrets_manager = KeeperSecretsManager.from_config(config_base64)

records = secrets_manager.get_secrets
```

`KeeperSecretsManager.new` が受け付けるキーワードオプション (`:hostname`、`:verify_ssl_certs`、`:proxy_url` など) は、第2引数のハッシュとしても指定できます。

#### 環境変数を使用する場合

環境変数から読み取り専用の構成をロードする場合:

```ruby
require 'keeper_secrets_manager'

# 事前に環境変数を設定:
# export KSM_HOSTNAME=keepersecurity.com
# export KSM_CLIENT_ID=your-client-id
# export KSM_PRIVATE_KEY=your-private-key
# export KSM_APP_KEY=your-app-key
# export KSM_SERVER_PUBLIC_KEY_ID=10

# 環境変数から構成をロード
config = KeeperSecretsManager::Storage::EnvironmentStorage.new('KSM_')
secrets_manager = KeeperSecretsManager.new(config: config)
```

### バインディングライフサイクル

ワンタイムトークンは、クライアント作成時ではなく、最初の `get_secrets()` 呼び出し時に引き換えられます。構成を外部ストア (AWS Secrets Manager、Azure Key Vaultなど) に永続化する場合は、その呼び出しの後にのみ読み出してください。詳しくは、[バインディングライフサイクル](/keeperpam/jp/secrets-manager/about/secrets-manager-configuration.md#binding-lifecycle)をご参照ください。

```ruby
require 'keeper_secrets_manager'

# 初回実行: ワンタイムトークンと永続ストレージパスを指定します。
secrets_manager = KeeperSecretsManager.from_file(
  'keeper_config.json',
  token: 'US:ONE_TIME_TOKEN'
)
records = secrets_manager.get_secrets  # Token is redeemed here; keeper_config.json is updated.

# 以降の実行: トークンを省略します。保存済みの認証情報を直接使用します。
secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')
records = secrets_manager.get_secrets
```

### シークレットの取得

#### シークレットの取得

```ruby
get_secrets(uids = nil, request_links: false)
```

| パラメータ           | 型               | 必須 | デフォルト   | 説明                                                                       |
| --------------- | --------------- | -- | ------- | ------------------------------------------------------------------------ |
| `uids`          | `Array<String>` | 任意 | `nil`   | 取得対象のレコードUID。`nil` または空の場合はすべてのシークレットを取得                                 |
| `request_links` | `Boolean`       | 任意 | `false` | `true` の場合、各返却レコードの `links` 配列にリンク認証情報エントリが入り、`record.get_links` でアクセス可能 |

**レスポンス:**

**型:** `Array<KeeperRecord>`

すべてのKeeperレコード、または指定したUIDに一致するレコードの配列。

#### 使用例

**すべてのシークレットを取得する場合:**

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# すべてのシークレットを取得
records = secrets_manager.get_secrets

records.each do |record|
  puts "#{record.title} (#{record.type})"
end
```

**UIDを指定してシークレットを取得する場合:**

```ruby
# 単一レコードをUIDで取得
records = secrets_manager.get_secrets(['RECORD_UID'])
record = records.first

# 複数UIDを指定して取得
uids = ['UID1', 'UID2', 'UID3']
records = secrets_manager.get_secrets(uids)
```

#### タイトルでシークレットを取得する場合

```ruby
# タイトルに一致するすべてのシークレットを取得
get_secrets_by_title(title)

# タイトルに一致する最初のシークレットを取得
get_secret_by_title(title)
```

| パラメータ   | 型        | 必須 | デフォルト | 説明                   |
| ------- | -------- | -- | ----- | -------------------- |
| `title` | `String` | 必須 | -     | 検索対象のレコードタイトル (完全一致) |

**レスポンス:**

**型:** `Array<KeeperRecord>` (`get_secrets_by_title`) または `KeeperRecord` (`get_secret_by_title`)

タイトルに一致するすべてのレコード、または最初に一致したレコード。

#### 使用例

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# タイトルが完全一致するシークレットを1件取得
record = secrets_manager.get_secret_by_title('My Database Credentials')

# 同じタイトルを持つ複数レコードを取得
records = secrets_manager.get_secrets_by_title('My Login')

# レコードからフィールドにアクセス
puts "Login: #{record.login}"
puts "Password: #{record.password}"
```

### リンク認証情報

PAMレコードにリンク認証情報がある場合、`get_secrets` に `request_links: true` を渡すと含められます。`record.get_links` を呼び出すと、生の `links` 配列を型付きの `Array<KeeperRecordLink>` として取得できます。

```ruby
records = secrets_manager.get_secrets(['PAM_RECORD_UID'], request_links: true)
record = records.first

links = record.get_links
links.each do |link|
  puts "Linked UID: #{link.record_uid}"
  puts "Admin user: #{link.admin_user?}"
  puts "Allows rotation: #{link.allows_rotation?}"
end
```

**`KeeperRecordLink` のアクセサ** (いずれも例外を発生させません。失敗時は `false` / `nil` を返します):

| アクセサ                                | 戻り値                | 説明                                                                  |
| ----------------------------------- | ------------------ | ------------------------------------------------------------------- |
| `record_uid`                        | `String`           | リンク先レコードのUID                                                        |
| `path`                              | `String` または `nil` | 識別子: `"meta"`、`"ai_settings"`、`"jit_settings"`、または認証情報リンクの場合は `nil` |
| `admin_user?`                       | `Boolean`          | 管理者権限を付与するリンク                                                       |
| `launch_credential?`                | `Boolean`          | 起動用認証情報のリンク                                                         |
| `iam_user?`                         | `Boolean`          | IAMユーザー認証情報のリンク                                                     |
| `allows_rotation?`                  | `Boolean`          | ローテーション許可 (`allowedSettings` を参照)                                   |
| `allows_connections?`               | `Boolean`          | 接続の許可                                                               |
| `allows_session_recording?`         | `Boolean`          | セッション録画の許可                                                          |
| `allows_port_forwards?`             | `Boolean`          | ポート転送の許可                                                            |
| `get_link_data(record_key)`         | `Hash` または `nil`   | パース済みのリンクデータ全体 (平文または復号済み)                                          |
| `get_decrypted_data(record_key)`    | `String` または `nil` | AES-256-GCMで復号したデータ文字列 (暗号化パス向け)                                    |
| `get_meta_data`                     | `Hash` または `nil`   | `"meta"` リンクからのPAMローテーション/接続設定                                      |
| `get_ai_settings_data(record_key)`  | `Hash` または `nil`   | `"ai_settings"` リンクからのAI設定                                          |
| `get_jit_settings_data(record_key)` | `Hash` または `nil`   | `"jit_settings"` リンクからのJIT設定                                        |

`record_key` は `record.record_key` (復号済みレコードキーのバイト列) で、暗号化されたリンクパス (`ai_settings`、`jit_settings`) でのみ必要です。平文JSONのリンクはキーなしでパースできます。

詳しくは、[リンク認証情報](/keeperpam/jp/secrets-manager/about/linked-credentials.md)をご参照ください。

### シークレットから値を取得する

シークレットを取得した後、フィールド値には複数の方法でアクセスできます。

#### 動的フィールドアクセスを使用する場合

```ruby
record = secrets_manager.get_secrets(['RECORD_UID']).first

# 標準フィールドに動的にアクセス
login = record.login
password = record.password
url = record.url

# 複合フィールドにアクセス
host = record.host  # Returns hash with hostName and port
```

#### 明示的なフィールドメソッドを使用する場合

```ruby
# 単一値の取得 (最初の値を返す)
login = record.get_field_value_single('login')

# 複数値の取得 (配列を返す)
passwords = record.get_field_value('password')

# ラベル付きカスタムフィールドへのアクセス
api_key = record.get_field_value_single('API Key')
environment = record.get_field_value_single('Environment')
```

#### Keeper表記法を使用する場合

```ruby
# URI形式のNotationを使ってフィールドにアクセス
password = secrets_manager.get_notation("keeper://#{record.uid}/field/password")

# レコードタイトルを使ってアクセス
url = secrets_manager.get_notation("keeper://My Login/field/url")

# 複合フィールドのプロパティにアクセス
hostname = secrets_manager.get_notation("keeper://#{record.uid}/field/host[hostName]")
port = secrets_manager.get_notation("keeper://#{record.uid}/field/host[port]")

# カスタムフィールドへアクセス
env = secrets_manager.get_notation("keeper://#{record.uid}/custom_field/Environment")
```

{% hint style="info" %}
Keeper表記法の形式と機能については、[Keeper表記法の資料](/keeperpam/jp/secrets-manager/about/keeper-notation.md)をご参照ください。
{% endhint %}

#### エラーセーフな表記法: `try_get_notation`

`try_get_notation` は `get_notation` の例外非発生ラッパーです。成功時は `Array` を返し、エラー時は空配列 `[]` を返すため、フィールドが存在しない場合に値なしとして扱いたいときは `rescue` ブロックなしで安全に使えます。

```ruby
# 無効な表記法やレコード欠落時に例外を発生させず [] を返す
values = secrets_manager.try_get_notation("keeper://#{record.uid}/field/password")
password = values.first  # nil if not found, no exception
```

`get_notation` は無効な入力に対して引き続き `NotationError` を発生させます。エラー時に処理を止めたい場合に適しています。

#### 配列表記法: `get_notation_results` と `try_get_notation_results`

`get_notation_results` は表記法URIを解決し、一致する値の **`Array` を常に返します**。複数値フィールド (例: `host` フィールド内の複数ホスト) ではすべての要素を保持します。無効な入力では `NotationError` を発生させます。

`try_get_notation_results` は例外非発生の派生です。エラーをログに記録し、例外の代わりに `[]` を返します。

```ruby
# 一致するすべての値を Array として返す
values = secrets_manager.get_notation_results("keeper://#{record.uid}/field/host")
# => [{"hostName"=>"db1.example.com","port"=>"5432"}, {"hostName"=>"db2.example.com","port"=>"5432"}]

# セーフ版 (例外を発生させない)
values = secrets_manager.try_get_notation_results("keeper://#{record.uid}/field/host")
# => [] if the notation is invalid or the record does not exist
```

対照的に、`get_notation` はスカラー (多くのセレクタでは最初の値) を返し、`try_get_notation` は `get_notation` を `Array()` で包みます。`try_get_notation` は値が1件だけの場合でも単一要素の配列を返します。複数値フィールドの全値セットが必要なときは `get_notation_results` を使用してください。

#### 参照フィールドの展開

一部のPAMレコードフィールドは、インライン値ではなく他レコードを参照するUIDを格納します。`inflate_field_value` は、参照先レコードを取得してフィールド値を直接返すことで、それらのUIDを解決します。

```ruby
inflate_field_value(uids, replace_fields)
```

| パラメータ            | 型               | 必須 | 説明                                       |
| ---------------- | --------------- | -- | ---------------------------------------- |
| `uids`           | `Array<String>` | 必須 | 解決対象の参照レコードUID                           |
| `replace_fields` | `Array<String>` | 必須 | 参照先レコードから抽出するフィールドタイプ (例: `['address']`) |

**レスポンス:**

**型:** `Array`。解決済みUIDごとに1エントリで、`nil` エントリは除去されます。各エントリは解決済みフィールド値 (`String`、`Hash`、またはネストした `Array`。フィールドタイプによる) です。

参照タイプが解決するフィールドタイプを調べるには、`get_inflate_ref_types` を呼び出します。

```ruby
get_inflate_ref_types(field_type)
```

| フィールドタイプ     | 解決先                                                |
| ------------ | -------------------------------------------------- |
| `addressRef` | `['address']`                                      |
| `cardRef`    | `['paymentCard', 'text', 'pinCode', 'addressRef']` |
| その他          | `[]` (不明な参照タイプは空配列)                                |

**使用例**

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

record = secrets_manager.get_secrets(['PAM_RECORD_UID']).first

# cardRef フィールドを探す
card_field = record.get_field('cardRef')
if card_field
  ref_uids   = card_field['value'] || []
  field_types = secrets_manager.get_inflate_ref_types('cardRef')
  inflated    = secrets_manager.inflate_field_value(ref_uids, field_types)
  inflated.each { |v| puts v.inspect }
end
```

### TOTPコードの取得

TOTPコードを生成するには、レコードからTOTP URLを取得し、`KeeperSecretsManager::TOTP` モジュールを使用します。TOTPの生成には、シークレットのデコード用に `base32` gem (`gem install base32`) が必要です。

```ruby
# レコードからTOTP URLを取得
totp_url = record.get_field_value_single('oneTimeCode')

# パースしてコードを生成
require 'keeper_secrets_manager/totp'
totp_params = KeeperSecretsManager::TOTP.parse_url(totp_url)
totp_code = KeeperSecretsManager::TOTP.generate_code(
  totp_params['secret'],
  algorithm: totp_params['algorithm'],
  digits: totp_params['digits'],
  period: totp_params['period']
)
```

| パラメータ       | 型         | 必須 | デフォルト    | 説明                              |
| ----------- | --------- | -- | -------- | ------------------------------- |
| `secret`    | `String`  | 必須 | -        | Base32形式でエンコードされたTOTPシークレット     |
| `algorithm` | `String`  | 任意 | `'SHA1'` | ハッシュアルゴリズム (SHA1、SHA256、SHA512) |
| `digits`    | `Integer` | 任意 | `6`      | コードの桁数                          |
| `period`    | `Integer` | 任意 | `30`     | 有効期間 (秒)                        |

**レスポンス:**

**型:** `String`

2要素認証に使用する現在のTOTP (Time-Based One-Time Password) コード。

#### 使用例

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# TOTPを含むレコードを取得
record = secrets_manager.get_secrets(['RECORD_UID']).first

# レコードからTOTP URLを取得
totp_url = record.get_field_value_single('oneTimeCode')

# TOTPパラメータをパース
require 'keeper_secrets_manager/totp'
totp_params = KeeperSecretsManager::TOTP.parse_url(totp_url)

# TOTPコードを生成
totp_code = KeeperSecretsManager::TOTP.generate_code(
  totp_params['secret'],
  algorithm: totp_params['algorithm'],
  digits: totp_params['digits'],
  period: totp_params['period']
)

puts "Current TOTP code: #{totp_code}"
puts "Expires in: #{30 - (Time.now.to_i % 30)} seconds"
```

### ランダムパスワードの生成

文字種や長さなどを指定して、暗号学的に安全なランダムパスワードを生成できます。シークレットをプログラムから作成または更新する際に便利です。

```ruby
KeeperSecretsManager::Utils.generate_password(
  length: 64,
  lowercase: 0,
  uppercase: 0,
  digits: 0,
  special_characters: 0
)
```

| パラメータ                | 型         | 必須 | デフォルト | 説明                              |
| -------------------- | --------- | -- | ----- | ------------------------------- |
| `length`             | `Integer` | 任意 | `64`  | パスワード全体の長さ                      |
| `lowercase`          | `Integer` | 任意 | `0`   | 小文字 (a-z) の最小数                  |
| `uppercase`          | `Integer` | 任意 | `0`   | 大文字 (A-Z) の最小数                  |
| `digits`             | `Integer` | 任意 | `0`   | 数字 (0-9) の最小数                   |
| `special_characters` | `Integer` | 任意 | `0`   | 記号 (!@#$%^&\*()\_+-=\[]{}) の最小数 |

**レスポンス:**

**型:** `String`

指定した要件を満たす、暗号学的に安全なランダムパスワード。

{% hint style="info" %}
この関数は、暗号学的に安全な乱数生成を行うRubyの `SecureRandom` を使用し、適切な文字分布を確保するためにFisher-Yatesシャッフルを適用します。
{% endhint %}

#### 使用例

**デフォルト設定で64文字のパスワードを生成する場合:**

```ruby
require 'keeper_secrets_manager'

# すべてデフォルト値で生成 (64文字のランダムパスワード)
password = KeeperSecretsManager::Utils.generate_password
puts "Generated: #{password}"
# => "Xk9$mP2..."  (64 characters)
```

**生成要件を指定する場合:**

```ruby
# 32文字で、各文字種の最低数を指定
password = KeeperSecretsManager::Utils.generate_password(
  length: 32,
  lowercase: 2,
  uppercase: 2,
  digits: 2,
  special_characters: 2
)

puts "Generated: #{password}"
# => "aB12$xY34..."  (32 chars with at least 2 of each type)

# 様々な要件で強度の高いパスワードを生成
password = KeeperSecretsManager::Utils.generate_password(
  length: 20,
  lowercase: 3,
  uppercase: 3,
  digits: 3,
  special_characters: 3
)
```

**新しいシークレットを作成する際に使用する場合:**

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# 生成したパスワードを使って新しいログインレコードを作成
record_data = {
  type: 'login',
  title: 'Production Database',
  fields: [
    { type: 'login', value: ['db_admin'] },
    {
      type: 'password',
      value: [KeeperSecretsManager::Utils.generate_password(
        length: 32,
        lowercase: 4,
        uppercase: 4,
        digits: 4,
        special_characters: 4
      )]
    },
    { type: 'url', value: ['https://db.example.com'] }
  ],
  notes: 'Auto-generated secure password'
}

# 必須のフォルダUIDを指定
options = KeeperSecretsManager::Dto::CreateOptions.new(folder_uid: 'FOLDER_UID')
record_uid = secrets_manager.create_secret(record_data, options)

puts "Created record with secure password: #{record_uid}"
```

**既存のシークレットを更新する際に使用する場合:**

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# 既存レコードを取得
record = secrets_manager.get_secrets(['RECORD_UID']).first

# 新しいパスワードを生成して設定
new_password = KeeperSecretsManager::Utils.generate_password(
  length: 40,
  lowercase: 5,
  uppercase: 5,
  digits: 5,
  special_characters: 5
)

record.password = new_password

# 変更を保存
secrets_manager.update_secret(record)

puts "Password updated with new secure value"
```

**パスワードローテーションスクリプト:**

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# 複数レコードのパスワードをローテーション
record_uids = ['UID1', 'UID2', 'UID3']

record_uids.each do |uid|
  record = secrets_manager.get_secrets([uid]).first

  # 新しいパスワードを生成
  new_password = KeeperSecretsManager::Utils.generate_password(
    length: 32,
    lowercase: 3,
    uppercase: 3,
    digits: 3,
    special_characters: 3
  )

  # レコードを更新
  record.password = new_password
  record.notes = "Password rotated on #{Time.now}"

  secrets_manager.update_secret(record)

  puts "✓ Rotated password for: #{record.title}"
end
```

### PAMレコードタイプ

PAMレコードは `record.type` で識別できます。

```ruby
records.each do |record|
  case record.type
  when 'pamMachine'
    # host field available
  when 'pamUser'
    # login field available
  when 'pamDatabase'
    # databaseType field available
  end
end
```

全11種類のPAMレコードタイプのフィールド定義は、[PAMレコードタイプ](/keeperpam/jp/secrets-manager/about/pam-record-types.md)をご参照ください。

### PAMローテーショントランザクション

`complete_transaction` は、ステージ済みのPAMローテーション更新を確定またはロールバックします。ローテーションワークフローでは、`update_secret` の後に呼び出して変更をサーバーにコミットします。

```ruby
complete_transaction(record_uid, rollback: false)
```

| パラメータ        | 型         | 必須 | デフォルト   | 説明                                 |
| ------------ | --------- | -- | ------- | ---------------------------------- |
| `record_uid` | `String`  | 必須 | -       | ステージ済みトランザクションを確定する対象レコードのUID      |
| `rollback`   | `Boolean` | 任意 | `false` | `true` の場合、コミットではなくステージ済み更新をロールバック |

**レスポンス:**

**型:** `Boolean`。成功時は `true`。

**使用例**

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

record = secrets_manager.get_secrets(['PAM_RECORD_UID']).first
record.password = 'NewRotatedPassword!'
secrets_manager.update_secret(record)

# ステージ済みローテーションをコミット
secrets_manager.complete_transaction(record.uid)

# または、ローテーション検証に失敗した場合はロールバック
# secrets_manager.complete_transaction(record.uid, rollback: true)
```

`update_secret` は変更をステージし、実際にコミットまたは破棄するのは `complete_transaction` です。`complete_transaction` を省略すると、変更はステージされたまま残ります。

### シークレットの更新

```ruby
update_secret(record)
```

| パラメータ    | 型              | 必須 | デフォルト | 説明                  |
| -------- | -------------- | -- | ----- | ------------------- |
| `record` | `KeeperRecord` | 必須 | -     | ボルト内で更新する、変更済みのレコード |

**レスポンス:**

**型:** `void`

変更された値を使って、ボルト内のシークレットを更新します。

#### 使用例

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# 既存レコードを取得
record = secrets_manager.get_secrets(['RECORD_UID']).first

# 動的アクセスでフィールドを更新
record.password = 'NewSecurePassword123!'

# 明示的メソッドでフィールドを更新
record.set_field('login', 'new_username@example.com')

# ノートを更新
record.notes = "Updated on #{Time.now}"

# 変更を保存
secrets_manager.update_secret(record)

puts "Secret updated successfully"
```

### 非確定保存: `save` と `save_with_options`

`save` は `complete_transaction` を呼び出さずにレコード更新をサーバーへ送信します。変更をステージしてから別途コミットまたはロールバックするPAMローテーションワークフローや、確定のための往復を発生させずにレコードを更新したい場合に使用します。

```ruby
save(record, transaction_type: nil, links_to_remove: nil)
```

| パラメータ              | 型                          | 必須 | デフォルト | 説明                                                  |
| ------------------ | -------------------------- | -- | ----- | --------------------------------------------------- |
| `record`           | `Dto::KeeperRecord`、`Hash` | 必須 | -     | 更新するレコード (`get_secrets` で取得済みであること)                 |
| `transaction_type` | `String` または `nil`         | 任意 | `nil` | PAMトランザクションタイプ (`'rotation'`、`'general'`、または `nil`) |
| `links_to_remove`  | `Array<String>`            | 任意 | `nil` | このレコードから削除するリンク先レコードのUID                            |

**レスポンス:**

**型:** `Boolean` (成功時は `true`)。

`UpdateOptions` を完全に制御する場合は、`save_with_options` を直接呼び出します。

```ruby
save_with_options(record, update_options = nil)
```

`update_options` は、`transaction_type:` と `links_to_remove:` 属性を持つ `Dto::UpdateOptions` オブジェクトです。

#### `update_secret` との比較

|                              | `update_secret` | `save` / `save_with_options` |
| ---------------------------- | --------------- | ---------------------------- |
| `complete_transaction` を呼び出す | はい (常に)         | いいえ                          |
| 更新後に `record.revision` を更新する | はい              | いいえ                          |
| キー取得のための追加の `get_secrets` 往復 | はい              | いいえ (既存キーを使用)                |
| 用途                           | 標準的なCRUD更新      | PAMステージング、バッチ更新、手動コミット制御     |

#### 使用例

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

record = secrets_manager.get_secrets(['PAM_RECORD_UID']).first
record.password = 'StagedNewPassword!'

# コミットせずに変更をステージ
secrets_manager.save(record, transaction_type: 'rotation')

# 後で: コミットまたはロールバック
if validation_passed?
  secrets_manager.complete_transaction(record.uid)
else
  secrets_manager.complete_transaction(record.uid, rollback: true)
end
```

### ファイルのダウンロード

```ruby
download_file(file)
```

| パラメータ  | 型            | 必須 | デフォルト | 説明                                  |
| ------ | ------------ | -- | ----- | ----------------------------------- |
| `file` | `KeeperFile` | 必須 | -     | ダウンロード対象となるKeeperRecord内のファイルオブジェクト |

**レスポンス:**

**型:** `Hash`

以下の情報を含むハッシュを返します。

* `'name'` - ファイル名
* `'data'` - バイナリ文字列としてのファイルデータ
* `'size'` - ファイルサイズ (バイト単位)
* `'type'` - ファイルのMIMEタイプ

#### 使用例

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# ファイルを含むレコードを取得
record = secrets_manager.get_secrets(['RECORD_UID']).first

# レコードにファイルがあるか確認
if record.files && record.files.any?
  # 最初のファイルをダウンロード
  file = record.files.first
  downloaded = secrets_manager.download_file(file)

  # ディスクに保存
  filename = downloaded['name'] || 'downloaded_file'
  File.write(filename, downloaded['data'])

  puts "Downloaded: #{filename}"
  puts "Size: #{downloaded['size']} bytes"
  puts "Type: #{downloaded['type']}"
end
```

### ファイルサムネイルのダウンロード

```ruby
download_thumbnail(file_data)
```

| パラメータ       | 型                       | 必須 | デフォルト | 説明                                  |
| ----------- | ----------------------- | -- | ----- | ----------------------------------- |
| `file_data` | `KeeperFile` または `Hash` | 必須 | -     | レコード内のファイルオブジェクト、または生のファイルメタデータハッシュ |

**レスポンス:**

**型:** `Hash`

以下の情報を含むハッシュを返します。

* `'file_uid'` - ファイルUID
* `'data'` - 復号済みサムネイル内容 (バイナリ文字列)
* `'size'` - サムネイルサイズ (バイト単位)

**使用例**

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')
record = secrets_manager.get_secrets(['RECORD_UID']).first

if record.files && record.files.any?
  file = record.files.first
  thumb = secrets_manager.download_thumbnail(file)
  File.write('thumbnail.jpg', thumb['data'], mode: 'wb') if thumb
end
```

### ファイルのアップロード

```ruby
upload_file(owner_record_uid, file_data, file_name, file_title = nil)
```

| パラメータ              | 型        | 必須 | デフォルト | 説明                    |
| ------------------ | -------- | -- | ----- | --------------------- |
| `owner_record_uid` | `String` | 必須 | -     | ファイルを添付する対象レコードのUID   |
| `file_data`        | `String` | 必須 | -     | ファイル内容 (バイナリまたはテキスト)  |
| `file_name`        | `String` | 必須 | -     | Keeper上でのファイル名        |
| `file_title`       | `String` | 任意 | `nil` | Keeper上でのファイルのタイトル/説明 |

**レスポンス:**

**型:** `String`

アップロードされたファイルのUID。

#### 使用例

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# ファイルをアップロード
file_uid = secrets_manager.upload_file(
  'RECORD_UID',                          # owner_record_uid
  File.read('/path/to/certificate.pem'), # file_data
  'certificate.pem',                      # file_name
  'Server Certificate'                    # file_title (optional)
)

puts "File uploaded with UID: #{file_uid}"

# テキストデータをアップロード
file_uid = secrets_manager.upload_file(
  'RECORD_UID',
  "server=localhost\nport=5432\n",
  'config.txt',
  'Database Config'
)
```

#### ファイルパスからのアップロード

`upload_file_from_path` はディスク上のファイルを自動で読み込むため、手動の `File.binread` 呼び出しは不要です。

```ruby
upload_file_from_path(owner_record_uid, file_path, file_title: nil)
```

| パラメータ              | 型        | 必須 | デフォルト | 説明                            |
| ------------------ | -------- | -- | ----- | ----------------------------- |
| `owner_record_uid` | `String` | 必須 | -     | ファイルを添付する対象レコードのUID           |
| `file_path`        | `String` | 必須 | -     | ディスク上のファイルへの絶対パスまたは相対パス       |
| `file_title`       | `String` | 任意 | ファイル名 | Keeper上に表示するタイトル。省略時はベースファイル名 |

**レスポンス:**

**型:** `String` (アップロードされたファイルのUID)。

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

file_uid = secrets_manager.upload_file_from_path(
  'RECORD_UID',
  '/path/to/certificate.pem',
  file_title: 'Server Certificate'
)

puts "Uploaded with UID: #{file_uid}"
```

### シークレットの作成

```ruby
create_secret(record_data, options = nil)
```

| パラメータ         | 型               | 必須 | デフォルト | 説明                                              |
| ------------- | --------------- | -- | ----- | ----------------------------------------------- |
| `record_data` | `Hash`          | 必須 | -     | レコード構造 (type、title、fields、custom、notes) を含むハッシュ |
| `options`     | `CreateOptions` | 必須 | -     | `folder_uid` (必須) と任意設定を含むCreateOptionsオブジェクト   |

**レスポンス:**

**型:** `String`

作成されたシークレットのUID。

**要件:**

* 共有フォルダUID (folder\_uidを指定する場合)
* 共有フォルダがシークレットマネージャーアプリケーションからアクセス可能であること
* 自身とシークレットマネージャーアプリケーションの両方に編集権限があること
* 共有フォルダ内に少なくとも1件のレコードが存在すること
* レコードのフィールド形式が正しく構成されていること (フィールドタイプの資料を参照)

#### 使用例

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# ログインレコードを新規作成
record_data = {
  type: 'login',
  title: 'Production Database',
  fields: [
    { type: 'login', value: ['db_admin'] },
    { type: 'password', value: ['SecurePassword123!'] },
    { type: 'url', value: ['https://db.example.com'] },
    {
      type: 'host',
      value: [{ hostName: '192.168.1.100', port: '5432' }],
      label: 'Database Host'
    }
  ],
  custom: [
    { type: 'text', label: 'Environment', value: ['Production'] },
    { type: 'text', label: 'Database Name', value: ['main_db'] }
  ],
  notes: 'Production database credentials'
}

# 必須のfolder_uidを指定してオプションを作成
options = KeeperSecretsManager::Dto::CreateOptions.new(folder_uid: 'FOLDER_UID')

# シークレットを作成
record_uid = secrets_manager.create_secret(record_data, options)

puts "Secret created with UID: #{record_uid}"

# 別の記述方法: オプションをインラインで渡す
record_uid = secrets_manager.create_secret(
  record_data,
  KeeperSecretsManager::Dto::CreateOptions.new(folder_uid: 'FOLDER_UID')
)
```

#### カスタムタイプレコードの作成

```ruby
# データベース認証情報レコードを作成
record_data = {
  type: 'databaseCredentials',
  title: 'MySQL Production',
  fields: [
    { type: 'text', label: 'Database Type', value: ['MySQL'] },
    {
      type: 'host',
      value: [{ hostName: 'mysql.example.com', port: '3306' }]
    },
    { type: 'login', value: ['root'] },
    { type: 'password', value: ['SecurePassword123!'] }
  ],
  notes: 'MySQL production database'
}

# 必須のfolder_uidを指定してオプションを作成
options = KeeperSecretsManager::Dto::CreateOptions.new(folder_uid: 'FOLDER_UID')
record_uid = secrets_manager.create_secret(record_data, options)
```

#### 事前取得したフォルダを使った作成

`create_secret_with_options` は `CreateOptions` オブジェクトと、任意の事前取得済みフォルダ一覧を受け取ります。同一セッションで複数レコードを作成し、すでにフォルダ一覧を保持している場合に使用します。内部の `get_folders` 呼び出しをスキップできるため、往復を削減できます。

```ruby
create_secret_with_options(create_options, record_data, folders: nil)
```

| パラメータ            | 型                          | 必須 | デフォルト | 説明                                                        |
| ---------------- | -------------------------- | -- | ----- | --------------------------------------------------------- |
| `create_options` | `Dto::CreateOptions`       | 必須 | -     | `folder_uid:` (必須) と `subfolder_uid:` (任意) を持つオプションオブジェクト |
| `record_data`    | `Dto::KeeperRecord`、`Hash` | 必須 | -     | 作成するレコード (`create_secret` と同じ形状)                          |
| `folders`        | `Array<KeeperFolder>`      | 任意 | `nil` | 事前取得したフォルダ一覧。`nil` の場合は自動取得                               |

**レスポンス:**

**型:** `String` (新規作成されたレコードのUID)。

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# フォルダを一度取得し、複数作成で再利用
folders = secrets_manager.get_folders
options = KeeperSecretsManager::Dto::CreateOptions.new(folder_uid: 'FOLDER_UID')

record_data = { type: 'login', title: 'My Record', fields: [] }
uid = secrets_manager.create_secret_with_options(options, record_data, folders: folders)
puts "Created: #{uid}"
```

`create_secret` は、一般的な単件作成向けの便利ラッパーで、内部で `create_secret_with_options` を呼び出します。

### シークレットの削除

```ruby
delete_secret(uids)
```

| パラメータ  | 型                            | 必須 | デフォルト | 説明                   |
| ------ | ---------------------------- | -- | ----- | -------------------- |
| `uids` | `String` または `Array<String>` | 必須 | -     | 削除対象のレコードUID (複数指定可) |

**レスポンス:**

**型:** `void`

指定したシークレットをボルトから削除します。

#### 使用例

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# 単一のシークレットを削除
secrets_manager.delete_secret('RECORD_UID')

puts "Secret deleted successfully"

# 複数のシークレットを削除
uids = ['UID1', 'UID2', 'UID3']
secrets_manager.delete_secret(uids)

puts "#{uids.length} secrets deleted"
```

### フォルダ

Ruby SDKでは、フォルダ操作に対して完全なCRUD (作成・取得・更新・削除) が利用できます。

#### フォルダの取得

```ruby
get_folders
```

**レスポンス:**

**型:** `Array<KeeperFolder>`

シークレットマネージャーアプリケーションがアクセス可能なすべてのフォルダ。

#### 使用例

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# すべてのフォルダを取得
folders = secrets_manager.get_folders

folders.each do |folder|
  puts "#{folder.name} (UID: #{folder.uid})"
end
```

#### フォルダパスの取得

```ruby
get_folder_path(folder_uid)
```

| パラメータ        | 型        | 必須 | デフォルト | 説明       |
| ------------ | -------- | -- | ----- | -------- |
| `folder_uid` | `String` | 必須 | -     | フォルダのUID |

**レスポンス:**

**型:** `String`

フォルダの完全なパス ("/" 区切りのパンくずリスト形式)。

#### 使用例

```ruby
# フォルダのパス (パンくずリスト形式) を取得
path = secrets_manager.get_folder_path('FOLDER_UID')
puts "Folder path: #{path}"  # "Parent/Child/Grandchild"
```

#### 名前でフォルダを検索

```ruby
find_folder_by_name(name, parent_uid: nil)
```

| パラメータ        | 型        | 必須 | デフォルト | 説明                      |
| ------------ | -------- | -- | ----- | ----------------------- |
| `name`       | `String` | 必須 | -     | 検索するフォルダ名               |
| `parent_uid` | `String` | 任意 | `nil` | 指定した親フォルダ内を対象に検索する場合に指定 |

**レスポンス:**

**型:** `KeeperFolder` または `nil`

最初に一致したフォルダ。一致しない場合はnil。

#### 使用例

```ruby
# 名前でフォルダを検索
folder = secrets_manager.find_folder_by_name('Finance')

# 特定の親フォルダ内でフォルダを検索
folder = secrets_manager.find_folder_by_name('Reports', parent_uid: 'PARENT_UID')
```

#### フォルダツリーの構築

```ruby
# フォルダマネージャーの取得
fm = secrets_manager.folder_manager

# フォルダツリー全体を構築
tree = fm.build_folder_tree

# ツリー構造をコンソールに出力
fm.print_tree

# フォルダ関係を取得
ancestors = fm.get_ancestors('FOLDER_UID')      # [parent, grandparent, ...]
descendants = fm.get_descendants('FOLDER_UID')   # [children, grandchildren, ...]
```

#### フォルダの作成

```ruby
create_folder(name, parent_uid:)
```

| パラメータ        | 型        | 必須 | デフォルト | 説明             |
| ------------ | -------- | -- | ----- | -------------- |
| `name`       | `String` | 必須 | -     | 作成するフォルダ名      |
| `parent_uid` | `String` | 必須 | -     | 親となる共有フォルダのUID |

**レスポンス:**

**型:** `String`

作成されたフォルダのUID。

#### 使用例

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# ルート階層 (共有フォルダ内) にフォルダを作成
folder_uid = secrets_manager.create_folder('New Folder', parent_uid: 'SHARED_FOLDER_UID')

puts "Folder created with UID: #{folder_uid}"

# 既存フォルダの下にサブフォルダを作成
subfolder_uid = secrets_manager.create_folder(
  'Subfolder',
  parent_uid: folder_uid
)

puts "Subfolder created: #{subfolder_uid}"
```

#### フォルダの更新

```ruby
update_folder(folder_uid, new_name)
```

| パラメータ        | 型        | 必須 | デフォルト | 説明           |
| ------------ | -------- | -- | ----- | ------------ |
| `folder_uid` | `String` | 必須 | -     | 更新対象フォルダのUID |
| `new_name`   | `String` | 必須 | -     | 新しいフォルダ名     |

**レスポンス:**

**型:** `void`

指定したフォルダの名前を変更します。

#### 使用例

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# フォルダ名を変更
secrets_manager.update_folder('FOLDER_UID', 'New Folder Name')

puts "Folder renamed successfully"
```

#### フォルダの削除

```ruby
delete_folder(folder_uid, force: false)
```

| パラメータ        | 型         | 必須 | デフォルト   | 説明                                         |
| ------------ | --------- | -- | ------- | ------------------------------------------ |
| `folder_uid` | `String`  | 必須 | -       | 削除対象のフォルダUID                               |
| `force`      | `Boolean` | 任意 | `false` | trueの場合、フォルダと内容物をすべて削除。falseの場合、空のフォルダのみ削除 |

**レスポンス:**

**型:** `void`

指定したフォルダをボルトから削除します。

#### 使用例

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')

# 空のフォルダを削除
secrets_manager.delete_folder('FOLDER_UID')

# フォルダを強制削除 (内容物もすべて削除)
secrets_manager.delete_folder('FOLDER_UID', force: true)

puts "Folder deleted"

# 複数フォルダを削除
folder_uids = ['UID1', 'UID2', 'UID3']
folder_uids.each do |uid|
  secrets_manager.delete_folder(uid, force: true)
end
```

### キャッシュ

シークレットをローカルにキャッシュすることで、パフォーマンスを向上できます。

#### CachingStorageの使用

```ruby
require 'keeper_secrets_manager'

# 基本ストレージを作成
base_storage = KeeperSecretsManager::Storage::FileStorage.new('keeper_config.json')

# キャッシュでラップ (TTLは600秒)
cached_storage = KeeperSecretsManager::Storage::CachingStorage.new(base_storage, 600)

# キャッシュ対応ストレージを使用
secrets_manager = KeeperSecretsManager.new(config: cached_storage)

# 最初の呼び出しではサーバーから取得
records = secrets_manager.get_secrets

# TTL内の呼び出しではキャッシュを使用
records = secrets_manager.get_secrets  # Uses cached data
```

#### 組み込みの災害復旧キャッシュ

`KeeperSecretsManager::CachingPostFunction` は、ドロップインの `custom_post_function` です。成功した各APIレスポンスを暗号化済みローカルキャッシュファイルに保存し、ネットワーク不可時にはそのキャッシュへ自動フォールバックします。Python、Java、JavaScript、.NET SDKにある災害復旧キャッシュのパターンと同等です。

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.from_file(
  'keeper_config.json',
  custom_post_function: KeeperSecretsManager::CachingPostFunction
)

# 成功時: レスポンスを ./ksm_cache.bin (または $KSM_CACHE_DIR/ksm_cache.bin) にキャッシュ
# ネットワーク障害時: 最後にキャッシュしたレスポンスへ透過的にフォールバック
records = secrets_manager.get_secrets
```

キャッシュファイルの場所のデフォルトは `./ksm_cache.bin` です。別ディレクトリへ移す場合は、環境変数 `KSM_CACHE_DIR` を設定します。

キャッシュを直接管理する場合:

```ruby
KeeperSecretsManager::Cache.cache_exists?     # Check whether a cache file is present
KeeperSecretsManager::Cache.clear_cache       # Delete the cache file
```

#### custom\_post\_function によるカスタムキャッシュ

高度なキャッシュ用途の場合:

```ruby
require 'keeper_secrets_manager'

# カスタムキャッシュを作成
cache = {}

custom_post = lambda do |url, payload|
  cache_key = "#{url}:#{payload}"

  # キャッシュを確認
  if cache[cache_key] && cache[cache_key][:expires_at] > Time.now
    return cache[cache_key][:response]
  end

  # 実際のリクエストを実行
  uri = URI(url)
  request = Net::HTTP::Post.new(uri)
  request['Content-Type'] = 'application/json'
  request.body = payload

  response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
    http.request(request)
  end

  # レスポンスを10分間キャッシュ
  cache[cache_key] = {
    response: response.body,
    expires_at: Time.now + 600
  }

  response.body
end

secrets_manager = KeeperSecretsManager.from_file(
  'keeper_config.json',
  custom_post_function: custom_post
)
```

## エラー処理

SDKには、エラー状況ごとに専用の例外クラスがあります。

```ruby
require 'keeper_secrets_manager'

begin
  secrets_manager = KeeperSecretsManager.from_file('keeper_config.json')
  records = secrets_manager.get_secrets

rescue KeeperSecretsManager::AuthenticationError => e
  puts "Authentication failed: #{e.message}"
  # Token expired or invalid

rescue KeeperSecretsManager::NetworkError => e
  puts "Network error: #{e.message}"
  # Connection timeout or DNS failure
  
rescue KeeperSecretsManager::ThrottledError => e
  puts "Rate limit exceeded: #{e.message}"
  # All automatic retries (up to 5) exhausted; back off before retrying

rescue KeeperSecretsManager::CryptoError => e
  puts "Encryption error: #{e.message}"
  # Decryption failed or key error
  
rescue KeeperSecretsManager::DecryptionError => e
  puts "Decryption failed: #{e.message}"
  # AES-GCM authentication tag failure; wrong key or tampered ciphertext

rescue KeeperSecretsManager::NotationError => e
  puts "Notation parsing error: #{e.message}"
  # Invalid notation URI format

rescue KeeperSecretsManager::Error => e
  puts "General error: #{e.message}"
  # Other SDK errors

rescue StandardError => e
  puts "Unexpected error: #{e.message}"
end
```

### 一般的なエラーシナリオ

```ruby
# レコード欠落を安全に処理
begin
  record = secrets_manager.get_secret_by_title('Nonexistent Record')
rescue KeeperSecretsManager::Error => e
  puts "Record not found: #{e.message}"
  # Provide fallback or create new record
end

# ネットワークエラー向けのリトライロジック
max_retries = 3
retries = 0

begin
  records = secrets_manager.get_secrets
rescue KeeperSecretsManager::NetworkError => e
  retries += 1
  if retries < max_retries
    sleep 2 ** retries  # Exponential backoff
    retry
  else
    raise
  end
end
```

## 高度な構成

### カスタムホスト名

```ruby
require 'keeper_secrets_manager'

# 欧州データセンター
secrets_manager = KeeperSecretsManager.new(
  token: 'EU:ONE_TIME_TOKEN',
  hostname: 'keepersecurity.eu',
  config: storage
)

# 豪州データセンター
secrets_manager = KeeperSecretsManager.new(
  token: 'AU:ONE_TIME_TOKEN',
  hostname: 'keepersecurity.com.au',
  config: storage
)
```

### SSL証明書検証

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.new(
  config: storage,
  verify_ssl_certs: true  # Default is true
)
```

### カスタムロギング

```ruby
require 'keeper_secrets_manager'
require 'logger'

# カスタムロガーを作成
logger = Logger.new(STDOUT)
logger.level = Logger::DEBUG

secrets_manager = KeeperSecretsManager.new(
  config: storage,
  logger: logger,
  log_level: Logger::DEBUG
)
```

### HTTPプロキシ

初期化時に `proxy_url:` を渡すと、SDKのすべての通信 (API呼び出し、ファイルアップロード、ファイルダウンロード) をHTTPまたはHTTPSプロキシ経由にできます。認証付きプロキシは、URLに認証情報を埋め込んで指定します。

```ruby
require 'keeper_secrets_manager'

# 明示的なプロキシ
secrets_manager = KeeperSecretsManager.from_file(
  'keeper_config.json',
  proxy_url: 'http://proxy.example.com:8080'
)

# 認証付きプロキシ
secrets_manager = KeeperSecretsManager.from_file(
  'keeper_config.json',
  proxy_url: 'http://user:password@proxy.example.com:8080'
)
```

`proxy_url:` を指定しない場合、SDKは環境変数 `HTTPS_PROXY` および `https_proxy` を自動的に確認します。

不正な `proxy_url` (不正な形式のURL、またはホスト欠落) は、初期化時に説明付きの `ArgumentError` を発生させます。

### すべての構成オプション

```ruby
require 'keeper_secrets_manager'

secrets_manager = KeeperSecretsManager.new(
  token: 'US:ONE_TIME_TOKEN',                   # One-time access token
  config: storage,                              # Storage implementation
  hostname: 'keepersecurity.com',               # API hostname
  verify_ssl_certs: true,                       # SSL verification
  proxy_url: 'http://proxy.example.com:8080',   # HTTP/HTTPS proxy (optional)
  logger: Logger.new(STDOUT),                   # Custom logger
  log_level: Logger::WARN,                      # Log level
  custom_post_function: my_post_func            # Custom HTTP handler
)
```

## フィールドタイプヘルパー

型付きフィールドを作成するための任意の便利メソッドです。

```ruby
require 'keeper_secrets_manager'

# タイプ安全のためにフィールドヘルパーを使用
fields = [
  KeeperSecretsManager::FieldTypes::Helpers.login('admin'),
  KeeperSecretsManager::FieldTypes::Helpers.password('SecurePass123!'),
  KeeperSecretsManager::FieldTypes::Helpers.url('https://example.com'),
  KeeperSecretsManager::FieldTypes::Helpers.host(
    hostname: '192.168.1.100',
    port: 22
  ),
  KeeperSecretsManager::FieldTypes::Helpers.name(
    first: 'John',
    middle: 'Q',
    last: 'Doe'
  ),
  KeeperSecretsManager::FieldTypes::Helpers.address(
    street1: '123 Main St',
    city: 'New York',
    state: 'NY',
    zip: '10001'
  )
]

# レコード作成用にハッシュへ変換
record_data = {
  type: 'login',
  title: 'Server with Helpers',
  fields: fields.map(&:to_h)
}

# 必須の folder_uid を指定して作成オプションを作成
options = KeeperSecretsManager::Dto::CreateOptions.new(folder_uid: 'FOLDER_UID')
record_uid = secrets_manager.create_secret(record_data, options)
```

## ダイナミックレコードアクセス

Ruby SDKでは、`method_missing` を利用してJavaScriptのような動的フィールドアクセスを実現しています。

```ruby
# レコードを取得
record = secrets_manager.get_secrets(['RECORD_UID']).first

# 動的ゲッター
login = record.login          # Returns field value
password = record.password    # Returns field value
url = record.url             # Returns field value

# 動的セッター
record.password = 'NewPassword123!'
record.url = 'https://newurl.example.com'

# フィールドが存在するか確認
if record.respond_to?(:oneTimeCode)
  # oneTimeCode フィールドからTOTPコードを生成
  require 'keeper_secrets_manager/totp'
  totp_url = record.oneTimeCode
  totp_params = KeeperSecretsManager::TOTP.parse_url(totp_url)
  totp_code = KeeperSecretsManager::TOTP.generate_code(
    totp_params['secret'],
    algorithm: totp_params['algorithm'],
    digits: totp_params['digits'],
    period: totp_params['period']
  )
end

# すべてのフィールドにハッシュ形式でアクセス
fields = record.fields
fields.each do |type, values|
  puts "#{type}: #{values.join(', ')}"
end
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.keeper.io/keeperpam/jp/secrets-manager/developer-sdk-library/ruby-sdk.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
