# Go SDK

<figure><img src="/files/BIfgblncuLOYCMX6jMER" alt=""><figcaption></figcaption></figure>

## 要件

Go SDKでは**Go 1.16以上**が必要です。

Goのバージョンを確認するには、以下のコマンドを実行します。

```bash
$ go version
```

アップグレードが必要な場合は<https://go.dev/dl/>をご参照ください。

{% hint style="warning" %}
**v1.7.0の破壊的変更:** 最低Goバージョンが1.16以上に引き上げられました。
{% endhint %}

## ダウンロードとインストール <a href="#download-and-installation" id="download-and-installation"></a>

### GitHubからインストール <a href="#install-from-github" id="install-from-github"></a>

Go SDKの最新リリースは、[GitHubのリポジトリ](https://github.com/Keeper-Security/secrets-manager-go)から入手できます。

```bash
$ go get github.com/keeper-security/secrets-manager-go/core
```

詳細については、[pkg.go.dev のパッケージドキュメント](https://pkg.go.dev/github.com/keeper-security/secrets-manager-go/core)をご参照ください。

### ソースコード <a href="#source-code" id="source-code"></a>

Goのソースコードは、[GitHubリポジトリ](https://github.com/keeper-security/secrets-manager-go)で入手できます。

## SDKの使用 <a href="#using-the-sdk" id="using-the-sdk"></a>

### 初期化 <a href="#initialize" id="initialize"></a>

{% hint style="info" %}
（後から再利用する場合）トークンのみで新しい構成を用意するには、読み取り操作を少なくとも 1 回実行し、トークンをバインドして `config.json` を完全に埋める必要があります。
{% endhint %}

シークレットを取得するには、まずシークレットマネージャーのクライアントを初期化します。

```go
package main

import (	
    ksm "github.com/keeper-security/secrets-manager-go/core"	
)

func main() {
	clientOptions := &ksm.ClientOptions{
		Token:  "[One Time Access Token]",
		Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	sm := ksm.NewSecretsManager(clientOptions)
	// トークンのみを使用して（後で使用するために）構成を生成するには
	// トークンをバインドするアクセス操作を少なくとも 1 回実行する必要があります
	//sm.GetSecrets([]string{})
}
```

**ClientOptions のパラメータ**

<table><thead><tr><th width="158.1484375">パラメータ</th><th width="171.421875">型</th><th width="114.85546875">必須</th><th width="125.6015625">デフォルト</th><th>説明</th></tr></thead><tbody><tr><td><code>Token</code></td><td><code>string</code></td><td>初回のみ</td><td>-</td><td>リージョンプレフィックス付きのワンタイムアクセストークン (例: <code>US:...</code>)。初回バインドに必要です。</td></tr><tr><td><code>Config</code></td><td><code>IKeyValueStorage</code></td><td>はい</td><td>-</td><td>構成の永続化用ストレージ実装 (ファイルまたはメモリ)。</td></tr><tr><td><code>HostName</code></td><td><code>string</code></td><td>いいえ</td><td>トークンから導出</td><td>サーバーホスト名の上書き。トークンのリージョンプレフィックスから自動算出されます。</td></tr><tr><td><code>VerifySslCerts</code></td><td><code>bool</code></td><td>いいえ</td><td><code>true</code></td><td>SSL証明書の検証の有効/無効。*</td></tr></tbody></table>

`NewSecretsManager` 関数は、指定したパラメータでシークレットマネージャーを初期化し、`ClientOptions` の設定を保存します。

```go
sm := ksm.NewSecretsManager(options)
```

### シークレットの取得 <a href="#retrieve-secrets" id="retrieve-secrets"></a>

```go
records, err := sm.GetSecrets([]string{})
```

| パラメータ  | 型          | 説明                                                       |
| ------ | ---------- | -------------------------------------------------------- |
| `uids` | `[]string` | 取得するレコードのUID。空のスライス `[]string{}` を渡すと、共有されているすべてのレコードを取得 |

**レスポンス**

型: `[]*Record`

指定したUIDのレコード。UIDを省略した場合は、シークレットマネージャーのクライアントと共有されているすべてのレコードです。

**使用例**

すべてのシークレットを取得

```go
package main

import (	
    ksm "github.com/keeper-security/secrets-manager-go/core"	
)

func main() {
	clientOptions := &ksm.ClientOptions{
		Token:  "[One Time Access Token]",
		Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	sm := ksm.NewSecretsManager(clientOptions)
	allRecords, err := sm.GetSecrets([]string{})
}

```

フィルタでシークレットを取得

```go
package main

import (	
    ksm "github.com/keeper-security/secrets-manager-go/core"	
)

func main() {
	clientOptions := &ksm.ClientOptions{
		Token:  "[One Time Access Token]",
		Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	sm := ksm.NewSecretsManager(clientOptions)
	records, err := sm.GetSecrets([]string{"[Secret UID]"})
}
```

### タイトルでシークレットを取得 <a href="#retrieve-secrets-by-title" id="retrieve-secrets-by-title"></a>

```go
// 一致するレコードをすべて取得
GetSecretsByTitle(recordTitle string) (records []*Record, err error)

// 最初に一致したレコードだけを取得
GetSecretByTitle(recordTitle string) (record *Record, err error)
```

| パラメータ         | 型        | 説明           |
| ------------- | -------- | ------------ |
| `recordTitle` | `string` | 検索するレコードタイトル |

**使用例**

```go
package main

// シークレットマネージャーのインポート
import (
  "fmt"
  ksm "github.com/keeper-security/secrets-manager-go/core"
)

func main() {

  options := &ksm.ClientOptions{
    // ワンタイムトークンは一度しか使用できません - 以後は、生成された設定ファイルを使用します
    Config: ksm.NewFileKeyValueStorage("ksm-config.json")}

  sm := ksm.NewSecretsManager(options)

  // タイトルが一致する最初の1件のレコードを取得
  aRecord, err := sm.GetSecretByTitle("My Credentials")
  if err != nil {
    fmt.Printf("Error retrieving record: %v\n", err)
    return
  }
  fmt.Printf("Found record: %s\n", aRecord.Title())

  // タイトルが一致するすべてのレコードを取得
  allRecords, err := sm.GetSecretsByTitle("My Credentials")
  
  if err != nil {
    fmt.Printf("Error retrieving records: %v\n", err)
    return
  }

  for _, record := range allRecords {
    fmt.Printf("UID %s, title [%s]\n", record.Uid, record.Title())
  }
}
```

### シークレットから値を取得 <a href="#get-values-from-a-secret" id="get-values-from-a-secret"></a>

**パスワードを取得**

{% tabs %}
{% tab title="パスワードを取得" %}

```go
(r *Record) Password() string
```

{% endtab %}

{% tab title="使用例" %}

```go
records, err := sm.GetSecrets([]string{"[Record UID]"})
if err != nil || len(records) == 0 {
    return
}
password := records[0].Password()
```

{% endtab %}
{% endtabs %}

**フィールド型から値を取得**

{% tabs %}
{% tab title="フィールド値を取得" %}

```go
(r *Record) GetFieldValueByType(fieldType string) string
```

{% endtab %}

{% tab title="例" %}

```go
records, err := sm.GetSecrets([]string{"[Record UID]"})
if err != nil || len(records) == 0 {
    return
}
login := records[0].GetFieldValueByType("login")
```

{% endtab %}
{% endtabs %}

| パラメータ       | 型        | 説明                        |
| ----------- | -------- | ------------------------- |
| `fieldType` | `string` | フィールド型 (例: `login`、`url`) |

一致する標準フィールドの先頭の値を文字列で返します。フィールドが存在しない場合は空文字列を返します。複数値や構造化フィールドには `GetFieldsByType` を使用します。

フィールド型はKeeperの[レコードタイプ](/enterprise-guide/jp/record-types.md)に基づきます。レコードタイプごとの利用可能なフィールドの一覧は、Keeperコマンダーの [record-type-info](/keeperpam/jp/commander-cli/command-reference/record-commands/record-type-commands.md#record-type-info-command) コマンドをご参照ください。

#### Keeper表記法を使用して値を取得 <a href="#retrieve-values-using-keeper-notation" id="retrieve-values-using-keeper-notation"></a>

**GetNotation**

{% tabs %}
{% tab title="Keeper表記法で取得" %}

```go
sm.GetNotation(query)
```

{% endtab %}

{% tab title="使用例" %}

```go
	clientOptions := &ksm.ClientOptions{
		Token:  "[One Time Access Token]",
		Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	sm := ksm.NewSecretsManager(clientOptions)

	// 指定したUIDを持つレコードからパスワードを取得
	value, err := sm.GetNotation("[Record UID]/field/password")
	if err == nil && len(value) > 0 {
		if password, ok := value[0].(string); ok {
			println("Successfully retrieved field value using notation")
		}
	}
```

{% endtab %}
{% endtabs %}

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

| パラメータ   | 型        | 説明                          |
| ------- | -------- | --------------------------- |
| `query` | `string` | 指定フィールドの値を取得するKeeper表記法のクエリ |

#### 戻り値 <a href="#returns" id="returns"></a>

型: `[]interface{}`

クエリに一致したフィールドの値

#### **GetNotationResults**

```go
(c *SecretsManager) GetNotationResults(notation string) ([]string, error)
(c *SecretsManager) TryGetNotationResults(notation string) []string
```

| パラメータ      | 型        | 説明            |
| ---------- | -------- | ------------- |
| `notation` | `string` | Keeper表記法のクエリ |

`GetNotationResults` はフィールド値を `[]string` として返します。値が文字列のときは `GetNotation` の代わりにこちらを使います。`TryGetNotationResults` はエラーを返さない版で、失敗時は空のスライスを返します。

**使用例**

```go
values, err := sm.GetNotationResults("[Record UID]/field/password")
if err == nil && len(values) > 0 {
    password := values[0]
}

password := ""
if values := sm.TryGetNotationResults("[Record UID]/field/password"); len(values) > 0 {
    password = values[0]
}
```

#### TOTPコードを取得 <a href="#retrieve-totp-code" id="retrieve-totp-code"></a>

{% tabs %}
{% tab title="TOTPコードを取得" %}

```go
GetTotpCode(url)
```

{% endtab %}

{% tab title="使用例" %}

```go
clientOptions := &ksm.ClientOptions{
	Token:  "[One Time Access Token]",
	Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
sm := ksm.NewSecretsManager(clientOptions)

urls, err := sm.GetNotation("[Record UID]/field/oneTimeCode")
if err == nil && len(urls) == 1 {
    url := urls[0].(string)
    totp, err := ksm.GetTotpCode(url)
    if err == nil {
        println(totp.Code, totp.TimeLeft)
    }
}
```

{% endtab %}
{% endtabs %}

<table data-header-hidden><thead><tr><th width="150">パラメータ</th><th width="150">型</th><th width="150">必須</th><th width="150">デフォルト</th><th>説明</th></tr></thead><tbody><tr><td>パラメータ</td><td>型</td><td>必須</td><td>デフォルト</td><td>説明</td></tr><tr><td><code>url</code></td><td><code>string</code></td><td>はい</td><td></td><td>TOTP の URL</td></tr></tbody></table>

### シークレットを更新 <a href="#update-a-secret" id="update-a-secret"></a>

{% hint style="warning" %}
レコード更新コマンドは、更新に成功してもローカル上のレコード内容は更新されません（改訂番号なども反映されません）。再取得せずに続けて更新すると、**改訂番号**の不一致で失敗します。更新のたびに、対象レコードを必ず再取得してください。
{% endhint %}

**パスワードを更新**

```go
(r *Record) SetPassword(password string) 
```

| パラメータ      | 型        | 必須 | デフォルト | 説明                |
| ---------- | -------- | -- | ----- | ----------------- |
| `password` | `string` | はい |       | レコードに設定する新しいパスワード |

**他のフィールドを更新**

```go
(r *Record) SetFieldValueSingle(field string, value string) 
```

| パラメータ   | 型        | 必須 | デフォルト | 説明           |
| ------- | -------- | -- | ----- | ------------ |
| `field` | `string` | はい |       | 更新するフィールドの名前 |
| `value` | `string` | はい |       | フィールドに設定する値  |

**ボルトのシークレットを更新**

レコードを保存すると、加えた変更がボルトに反映されます。

```go
(c *SecretsManager) Save(record *Record) (err error)
```

| パラメータ    | 型         | 説明                   |
| -------- | --------- | -------------------- |
| `record` | `*Record` | 保存する更新済みフィールドを含むレコード |

**使用例**

パスワードを更新

```go
package main

import (
  "fmt"
  ksm "github.com/keeper-security/secrets-manager-go/core"
)

func main() {
  clientOptions := &ksm.ClientOptions{
    Token:  "[One Time Access Token]",
    Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
  sm := ksm.NewSecretsManager(clientOptions)

  records, err := sm.GetSecrets([]string{"[Record UID]"})
  if err != nil {
    fmt.Printf("Error: %v\n", err)
    return
  }

  if len(records) == 0 {
    fmt.Println("No records found")
    return
  }

  record := records[0]
  record.SetPassword("NewPassword123$")

  err = sm.Save(record)
  if err != nil {
    fmt.Printf("Error saving record: %v\n", err)
    return
  }

  record.SetPassword("NewPassword1234$")

  err = sm.SaveBeginTransaction(record, ksm.TransactionTypeRotation)
  if err != nil {
    fmt.Printf("Error starting transaction: %v\n", err)
    return
  }

  success := rotateRemoteSshPassword("NewPassword1234$")

  err = sm.CompleteTransaction(record.Uid, !success)
  if err != nil {
    fmt.Printf("Error completing transaction: %v\n", err)
    return
  }
}

func rotateRemoteSshPassword(newPassword string) bool {
  return true
}
```

{% hint style="info" %}
`CompleteTransaction(uid, rollback bool)` では、`false` を渡すとローテーションをコミットし、`true` を渡すとロールバックします。例では `!success` を渡しており、ローテーション関数が `false` (失敗) を返したときに `true` (ロールバック) になります。
{% endhint %}

他のフィールドを更新

```go
package main

import (
  "fmt"
  ksm "github.com/keeper-security/secrets-manager-go/core"
)

func main() {
  clientOptions := &ksm.ClientOptions{
    Token:  "[One Time Access Token]",
    Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
  sm := ksm.NewSecretsManager(clientOptions)

  records, err := sm.GetSecrets([]string{"[Record UID]"})
  if err != nil {
    fmt.Printf("Error: %v\n", err)
    return
  }

  if len(records) == 0 {
    fmt.Println("No records found")
    return
  }

  record := records[0]
  record.SetFieldValueSingle("login", "New Login Value")
  record.SetTitle("New Title")
  record.SetNotes("Updated notes with additional context")

  err = sm.Save(record)
  if err != nil {
    fmt.Printf("Error saving record: %v\n", err)
    return
  }
}
```

{% hint style="info" %}
**v1.7.0**: `SetNotes` はUPSERT動作になり、レコードにメモフィールドが存在しない場合は作成します。v1.6.x以前では、メモのないレコードに対する `SetNotes` は何も行いませんでした。
{% endhint %}

レコードの各フィールド型はクラスとして表現されます。値を正しく扱うには、フィールドを対応する型にキャストします。フィールド型の一覧は、[レコードタイプ](/enterprise-guide/jp/record-types.md)のドキュメントをご参照ください。

#### ランダムなパスワードを生成 <a href="#generate-a-random-password" id="generate-a-random-password"></a>

{% tabs %}
{% tab title="パスワードを生成" %}

```go
GeneratePassword(length, lowercase, uppercase, digits, specialCharacters, specialCharacterSet)
```

{% endtab %}

{% tab title="使用例" %}

```go
allRecords, err := sm.GetSecrets([]string{})
if err != nil {
  fmt.Printf("Error: %v\n", err)
  return
}

if len(allRecords) == 0 {
  fmt.Println("No records found")
  return
}

record := allRecords[0]

password, err := ksm.GeneratePassword(64, "", "", "", "", "")
if err != nil {
  fmt.Printf("Error generating password: %v\n", err)
  return
}

record.SetPassword(password)

err = sm.Save(record)
if err != nil {
  fmt.Printf("Error saving record: %v\n", err)
  return
}
```

{% endtab %}
{% endtabs %}

| パラメータ                 | 型        | 説明                                                       |
| --------------------- | -------- | -------------------------------------------------------- |
| `length`              | `int`    | パスワード長。`0` 以下を渡すとデフォルト (32文字) を使用します                     |
| `lowercase`           | `string` | 小文字の最小数。最小を設けない場合は `""`                                  |
| `uppercase`           | `string` | 大文字の最小数。最小を設けない場合は `""`                                  |
| `digits`              | `string` | 数字の最小数。最小を設けない場合は `""`                                   |
| `specialCharacters`   | `string` | 記号の最小数。最小を設けない場合は `""`                                   |
| `specialCharacterSet` | `string` | 使用する記号の集合。`""` の場合はデフォルト `"!@#$%()+;<>=?[]{}^.,"` を使用します |

### ファイルのダウンロード <a href="#download-a-file" id="download-a-file"></a>

**DownloadFileByTitle**

```go
(r *Record) DownloadFileByTitle(title string, path string) error
```

| パラメータ   | 型        | 説明            |
| ------- | -------- | ------------- |
| `title` | `string` | ダウンロードするファイル名 |
| `path`  | `string` | 保存先のパス        |

**レスポンス**

型: `error`

成功時は `nil` を返します。失敗時は、タイトル不一致・ディレクトリ不存在・書き込み失敗などを示すエラーを返します。ログ出力や上位へのラップに利用します。

**使用例**

```go
import (
  "fmt"
  ksm "github.com/keeper-security/secrets-manager-go/core"
)

clientOptions := &ksm.ClientOptions{
  Token:  "[One Time Access Token]",
  Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
sm := ksm.NewSecretsManager(clientOptions)

records, err := sm.GetSecrets([]string{"[Record UID]"})
if err != nil {
  fmt.Printf("Error: %v\n", err)
  return
}

if len(records) == 0 {
  fmt.Println("No records found")
  return
}

record := records[0]

record.DownloadFileByTitle("certs.txt","secret_files/certs.txt")
```

***

**DownloadFile**

```go
(r *Record) DownloadFile(fileUid string, path string) error
```

| パラメータ     | 型        | 説明               |
| --------- | -------- | ---------------- |
| `fileUid` | `string` | ダウンロードするファイルのUID |
| `path`    | `string` | 保存先のパス           |

**レスポンス**

型: `error`

**使用例**

```go
records, err := sm.GetSecrets([]string{"[Record UID]"})
if err != nil || len(records) == 0 {
    return
}
for _, file := range records[0].Files {
    if err := records[0].DownloadFile(file.Uid, "/tmp/"+file.Name); err != nil {
        fmt.Printf("error downloading %s: %v\n", file.Name, err)
    }
}
```

***

**SaveFile**

```go
(f *KeeperFile) SaveFile(path string, createFolders bool) error
```

| パラメータ           | 型        | 説明                           |
| --------------- | -------- | ---------------------------- |
| `path`          | `string` | 書き込み先のフルパス                   |
| `createFolders` | `bool`   | `true` のとき、親ディレクトリがなければ作成します |

**レスポンス**

型: `error`

`record.Files` から得た `*KeeperFile` に対して使用します。

**使用例**

```go
records, err := sm.GetSecrets([]string{"[Record UID]"})
if err != nil || len(records) == 0 {
    return
}
for _, file := range records[0].Files {
    if err := file.SaveFile("/tmp/"+file.Name, true); err != nil {
        fmt.Printf("error saving %s: %v\n", file.Name, err)
    }
}
```

### ファイルのアップロード <a href="#upload-a-file" id="upload-a-file"></a>

```go
UploadFile(record *Record, file *KeeperFileUpload) (uid string, err error)
```

<table><thead><tr><th width="184.14763231197773">パラメータ</th><th width="206.99431983802478">型</th><th width="150">必須</th><th>説明</th></tr></thead><tbody><tr><td><code>ownerRecord</code></td><td><code>Record</code></td><td>はい</td><td>アップロードされたファイルを添付するレコード</td></tr><tr><td><code>file</code></td><td><code>KeeperFileUpload</code></td><td>はい</td><td>アップロードするファイル</td></tr></tbody></table>

```go
type KeeperFileUpload struct {
	Name  string
	Title string
	Type  string
	Data  []byte
}
```

<table><thead><tr><th width="169">パラメータ</th><th width="150">型</th><th width="150">必須</th><th>説明</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>string</code></td><td>はい</td><td>アップロード後にKeeperに格納されるファイルの名前</td></tr><tr><td><code>title</code></td><td><code>string</code></td><td>はい</td><td>アップロード後にKeeperに格納されるファイルのタイトル</td></tr><tr><td><code>type</code></td><td><code>string</code></td><td>はい</td><td>ファイルのデータのMIMEタイプ（「application/octet-stream」など）</td></tr><tr><td><code>data</code></td><td><code>[]byte</code></td><td>はい</td><td>バイト型のファイルデータ</td></tr></tbody></table>

**使用例**

```go
package main

import (
  "fmt"
  "os"

  ksm "github.com/keeper-security/secrets-manager-go/core"
)

func main() {

  options := &ksm.ClientOptions{
    Config: ksm.NewFileKeyValueStorage("ksm-config.json")}

  sm := ksm.NewSecretsManager(options)

  allRecords, err := sm.GetSecrets([]string{"[Record UID]"})
  if err != nil {
    fmt.Printf("Error: %v\n", err)
    return
  }

  if len(allRecords) == 0 {
    fmt.Println("No records found")
    return
  }

  ownerRecord := allRecords[0]

  dat, err := os.ReadFile("/myFile.json")
  if err != nil {
    fmt.Printf("Error reading file: %v\n", err)
    return
  }

  myFile := ksm.KeeperFileUpload{
    Name:  "myFile.json",
    Title: "My File",
    Type:  "application/json",
    Data:  dat,
  }

  _, err = sm.UploadFile(ownerRecord, &myFile)
  if err != nil {
    fmt.Printf("Error uploading file: %v\n", err)
    return
  }

  fmt.Println("File uploaded successfully")
}
```

### ファイルパスからアップロード <a href="#upload-a-file-from-path" id="upload-a-file-from-path"></a>

```go
(c *SecretsManager) UploadFilePath(record *Record, filePath string) (uid string, err error)
```

| パラメータ      | 型         | 説明                  |
| ---------- | --------- | ------------------- |
| `record`   | `*Record` | ファイルを添付するレコード       |
| `filePath` | `string`  | アップロードするローカルファイルのパス |

**レスポンス**

型: `string`, `error`

アップロードされた添付ファイルのUIDを返します。ディスクから直接アップロードする場合に `UploadFile` の代わりに使います。ファイルを読み込み、MIMEタイプを推定して内部で `UploadFile` を呼び出します。

**使用例**

```go
records, err := sm.GetSecrets([]string{"[Record UID]"})
if err != nil || len(records) == 0 {
    return
}
uid, err := sm.UploadFilePath(records[0], "/path/to/myFile.json")
if err != nil {
    fmt.Printf("error uploading file: %v\n", err)
    return
}
fmt.Printf("uploaded file UID: %s\n", uid)
```

### レコードからファイルを削除する

`SaveWithOptions()` 呼び出し時に `LinksToRemove` にファイルUIDを指定すると、レコードからファイルを外せます。

```go
import (
    "fmt"
    ksm "github.com/keeper-security/secrets-manager-go/core"
)

func removeFileFromRecord(sm *ksm.SecretsManager, recordUid string, fileUid string) error {
    records, err := sm.GetSecrets([]string{recordUid})
    if err != nil {
        return err
    }

    if len(records) == 0 {
        return fmt.Errorf("record not found: %s", recordUid)
    }

    record := records[0]

    updateOptions := ksm.UpdateOptions{
        LinksToRemove: []string{fileUid},
    }

    err = sm.SaveWithOptions(record, updateOptions)
    if err != nil {
        return fmt.Errorf("failed to remove file: %w", err)
    }

    fmt.Printf("File %s removed from record %s\n", fileUid, recordUid)
    return nil
}
```

**複数ファイルの削除:**

```go
updateOptions := ksm.UpdateOptions{
    LinksToRemove: []string{"FILE_UID_1", "FILE_UID_2", "FILE_UID_3"},
}
err := sm.SaveWithOptions(record, updateOptions)
```

### UpdateOptions

`UpdateOptions` は `SaveWithOptions` および `SaveBeginTransaction` のオプション動作を制御します。

| フィールド             | 型                       | 説明                                        |
| ----------------- | ----------------------- | ----------------------------------------- |
| `TransactionType` | `UpdateTransactionType` | 二相のトランザクション更新には `Rotation` を指定。通常の保存では省略。 |
| `LinksToRemove`   | `[]string`              | 保存時にレコードから切り離すファイルのUID。                   |

### シークレットの作成 <a href="#create-a-secret" id="create-a-secret"></a>

#### 要件 <a href="#prerequisites" id="prerequisites"></a>

* 共有フォルダのUID
  * 共有フォルダには、シークレットマネージャーアプリケーションからアクセスできる必要があります
  * ユーザーとシークレットマネージャーアプリケーションの双方に編集権限が必要です
  * 共有フォルダには、少なくとも1つのレコードが存在する必要があります
* 作成されたレコードとレコードのフィールドは正しく書式設定されている必要があります
  * レコードタイプごとのフィールド形式の詳細は、[レコードタイプ定義](/enterprise-guide/jp/record-types.md)をご参照ください
* TOTPフィールドには、KSM SDKの外で生成したURLのみを指定できます
* レコード作成後は、[ファイルのアップロード](#upload-a-file)の `UploadFile` を使ってファイル添付をアップロードできます

{% tabs %}
{% tab title="レコードを作成" %}

<pre class="language-go"><code class="lang-go"><strong>secretsManager.CreateSecretWithRecordData(recordUid, folderUid, record)
</strong></code></pre>

| パラメータ       | 型               |  必須 | デフォルト           |
| ----------- | --------------- | :-: | --------------- |
| `recordUid` | `string`        | いいえ | 自動生成されたランダムなUID |
| `folderUid` | `string`        |  はい |                 |
| `record`    | `*RecordCreate` |  はい |                 |

`recordUid` は任意です。`""` を渡すと、SDKがUIDを自動生成します。
{% endtab %}

{% tab title="サブフォルダにレコードを作成" %}

<pre class="language-go"><code class="lang-go"><strong>secretsManager.CreateSecretWithRecordDataAndOptions(createOptions, recordData, folders)
</strong></code></pre>

| パラメータ           | 型                 |  必須 | デフォルト |
| --------------- | ----------------- | :-: | ----- |
| `createOptions` | `*CreateOptions`  |  はい |       |
| `recordData`    | `*RecordCreate`   |  はい |       |
| `folders`       | `[]*KeeperFolder` | いいえ |       |

`folders` に `nil` を渡すと、SDKがフォルダ一覧を自動取得します。
{% endtab %}

{% tab title="ログインレコードの例" %}
この例では、ログイン値と生成されたパスワードを含むログインタイプのレコードを作成します。

{% hint style="info" %}
例に含まれる `[FOLDER UID]` を、シークレットマネージャーがアクセスできる共有フォルダのUIDに置き換えてください。
{% endhint %}

```go
package main

import (
  "fmt"
  ksm "github.com/keeper-security/secrets-manager-go/core"
)

func main() {
  clientOptions := &ksm.ClientOptions{
    Token:  "[One Time Access Token]",
    Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
  sm := ksm.NewSecretsManager(clientOptions)

  newLoginRecord := ksm.NewRecordCreate("login", "Sample KSM Record: Go SDK")

  password, err := ksm.GeneratePassword(32, "", "", "", "", "")
  if err != nil {
    fmt.Printf("Error generating password: %v\n", err)
    return
  }

  newLoginRecord.Fields = append(newLoginRecord.Fields,
    ksm.NewLogin("username@email.com"),
    ksm.NewPassword(password))

  newLoginRecord.Notes = "This is a Go record creation example"

  recordUid, err := sm.CreateSecretWithRecordData("", "[FOLDER UID]", newLoginRecord)
  if err != nil {
    fmt.Printf("Error creating record: %v\n", err)
    return
  }

  fmt.Printf("Record created with UID: %s\n", recordUid)
}
```

{% endtab %}

{% tab title="カスタムタイプの例" %}
{% hint style="info" %}
例に含まれる `[FOLDER UID]` を、シークレットマネージャーがアクセスできる共有フォルダのUIDに置き換えてください。
{% endhint %}

この例では、カスタムのレコードタイプのレコードを作成します。

```go
package main

import (
  "fmt"
  ksm "github.com/keeper-security/secrets-manager-go/core"
)

func main() {
  clientOptions := &ksm.ClientOptions{
    Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
  sm := ksm.NewSecretsManager(clientOptions)

customLogin := ksm.NewRecordCreate("Custom Login", "Sample Custom Type KSM Record: Go SDK")
password, err := ksm.GeneratePassword(32, "", "", "", "", "")
if err != nil {
  fmt.Printf("Error generating password: %v\n", err)
  return
}
customLogin.Fields = append(customLogin.Fields,
	ksm.NewHosts(ksm.Host{Hostname:"127.0.0.1", Port:"8080"}),
	ksm.NewLogin("login@email.com"),
	ksm.NewPassword(password),
	ksm.NewUrl("http://localhost:8080/login"),
	ksm.NewSecurityQuestions(ksm.SecurityQuestion{Question:"What is one plus one (write just a number)", Answer:"2"}),
	ksm.NewPhones(ksm.Phone{Region:"US", Number:"510-444-3333", Ext:"2345", Type:"Mobile"}),
	ksm.NewDate(1641934793000),
	ksm.NewNames(ksm.Name{First:"John", Middle:"Patrick", Last:"Smith"}),
	ksm.NewOneTimeCode("otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example"),
)
customLogin.Custom = append(customLogin.Custom,
	ksm.NewPhones(ksm.Phone{Region:"US", Number:"510-222-5555", Ext:"99887", Type:"Mobile"}),
	ksm.NewPhones(ksm.Phone{Region:"US", Number:"510-111-3333", Ext:"45674", Type:"Mobile"}),
)
customLogin.Notes = "\tThis custom type record was created\n\tvia Go SDK copied from https://docs.keeper.io/secrets-manager/secrets-manager/developer-sdk-library/golang-sdk"

recordUid, err := sm.CreateSecretWithRecordData("", "[FOLDER UID]", customLogin)
if err != nil {
  fmt.Printf("Error creating record: %v\n", err)
  return
}

fmt.Printf("Custom record created with UID: %s\n", recordUid)
}
```

{% endtab %}
{% endtabs %}

### シークレットの削除 <a href="#delete-a-secret" id="delete-a-secret"></a>

GoのKSM SDKでは、Keeperボルトのレコードを削除できます。

{% tabs %}
{% tab title="シークレットの削除" %}

```go
statuses, err := secretsManager.DeleteSecrets(recordUids)
```

| パラメータ        | 型          | 説明           |
| ------------ | ---------- | ------------ |
| `recordUids` | `[]string` | 削除するレコードのUID |

| 戻り値        | 型                   | 説明         |
| ---------- | ------------------- | ---------- |
| `statuses` | `map[string]string` | UIDごとの削除結果 |
| `err`      | `error`             | エラー (ある場合) |

ボルトに存在しない、またはKSMアプリケーションからアクセスできないUIDは黙ってスキップされ、エラーにはなりません。
{% endtab %}

{% tab title="例" %}

```go
import (
  "fmt"
  ksm "github.com/keeper-security/secrets-manager-go/core"
)

func main() {
  options := &ksm.ClientOptions{
    Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
  secretsManager := ksm.NewSecretsManager(options)

  statuses, err := secretsManager.DeleteSecrets([]string{"EG6KdJaaLG7esRZbMnfbFA"})
  if err != nil {
    fmt.Printf("Error deleting secrets: %v\n", err)
    return
  }

  for uid, status := range statuses {
    fmt.Printf("%s: %s\n", uid, status)
  }
}
```

{% endtab %}
{% endtabs %}

### キャッシュ <a href="#caching" id="caching"></a>

ネットワークに接続できないときでもシークレットを参照できるよう、Go SDKでシークレットを暗号化したファイルとしてローカルにキャッシュできます。

**キャッシュの設定と構成**

キャッシュを有効にするには、`SetCache(cache ICache)` を呼び出し、組み込みのメモリまたはファイルベースの実装のいずれかを渡すか、独自の `ICache` 実装を渡します。

```go
type ICache interface {
	SaveCachedValue(data []byte) error
	GetCachedValue() ([]byte, error)
	Purge() error
}
```

Go SDKには、メモリベースとファイルベースのキャッシュ実装があらかじめ用意されています。

```go
options := &ksm.ClientOptions{Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
sm := ksm.NewSecretsManager(options)

// メモリベースのキャッシュ
memCache := ksm.NewMemoryCache()
sm.SetCache(memCache)

// ファイルベースのキャッシュ
fileCache := ksm.NewFileCache("ksm_cache.bin")
sm.SetCache(fileCache)
```

オフライン時のフォールバック動作を示す完全な `ICache` 実装の例は、SDKリポジトリの [`example/custom-cache/main.go`](https://github.com/keeper-security/secrets-manager-go/blob/main/example/custom-cache/main.go) をご参照ください。

SDKは常にまずライブのネットワーク要求を試みます。キャッシュは、サーバーがHTTP 200以外を返した場合、またはDNS解決失敗・接続拒否・TLSハンドシェイク失敗・タイムアウトなどトランスポート層での失敗があった場合にフォールバックとして参照されます。ネットワーク層のエラーでキャッシュからレコードが返されると警告がログに出力されます。`GetSecrets` が成功するたびに、キャッシュは最新のレスポンスで更新されます。

{% hint style="warning" %}
**直近のリクエストのみ**: キャッシュは最も新しいレスポンスだけを保持します。最後に成功した呼び出しがUIDフィルタ付きだった場合、キャッシュフォールバックではそのレコードだけが返り、アプリケーションに共有されているすべてのレコードは返りません。キャッシュの使い方はこの点を踏まえて設計してください。
{% endhint %}

{% hint style="warning" %}
**更新後**: レコードを保存するとボルト上のリビジョンが変わります。更新後にキャッシュへフォールバックすると、キャッシュのリビジョンは古いままとなり、同じレコードへの続けての更新はリビジョン不一致で失敗します。保存のたびに `GetSecrets` を呼び出してキャッシュを更新してください。
{% endhint %}

### フォルダ <a href="#folders" id="folders"></a>

フォルダでは、作成・読み取り・更新・削除 (CRUD) の操作がすべて利用できます。

### フォルダの読み取り <a href="#read-folders" id="read-folders"></a>

フォルダの完全な階層構造をダウンロードします。

```go
GetFolders() ([]*KeeperFolder, error)
```

**レスポンス**

型: `[]*KeeperFolder, error`

**使用例**

```go
package main

import (
  "fmt"
  ksm "github.com/keeper-security/secrets-manager-go/core"
)

func main() {
  options := &ksm.ClientOptions{Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
  sm := ksm.NewSecretsManager(options)

  folders, err := sm.GetFolders()
  if err != nil {
    fmt.Printf("Error: %v\n", err)
    return
  }

  fmt.Printf("Retrieved %d folder(s)\n", len(folders))
}
```

### フォルダの作成 <a href="#create-a-folder" id="create-a-folder"></a>

フォルダの作成には `CreateOptions` とフォルダ名が必要です。`CreateOptions` のフォルダ UID パラメータ (共有フォルダの UID) は必須で、サブフォルダの UID は任意です。サブフォルダの UID を省略した場合、新しいフォルダは親 (共有フォルダ) の直下に作成されます。サブフォルダは共有フォルダの直下でなくても構いません。階層の深さはさまざまです。

```go
CreateFolder(createOptions CreateOptions, folderName string, folders []*KeeperFolder) (folderUid string, err error)
```

<table><thead><tr><th width="209.85161529417937">パラメータ</th><th width="206.99431983802478">型</th><th width="150">必須</th><th>説明</th></tr></thead><tbody><tr><td><code>createOptions</code></td><td><code>CreateOptions</code></td><td>はい</td><td>親およびサブフォルダのUID</td></tr><tr><td><code>folderName</code></td><td><code>string</code></td><td>はい</td><td>フォルダ名</td></tr><tr><td><code>folders</code></td><td><code>[]*KeeperFolder</code></td><td>いいえ</td><td>CreateOptionsで作成した親とサブフォルダの検索に使用するフォルダのリスト</td></tr></tbody></table>

```go
type CreateOptions struct {
	FolderUid    string
	SubFolderUid string
}
```

```go
type KeeperFolder struct {
	FolderKey []byte
	FolderUid string
	ParentUid string
	Name      string
}
```

**使用例**

```go
package main

import ksm "github.com/keeper-security/secrets-manager-go/core"

func main() {
	options := &ksm.ClientOptions{Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	sm := ksm.NewSecretsManager(options)

	co := ksm.CreateOptions{FolderUid: "[PARENT_SHARED_FOLDER_UID]", SubFolderUid: ""}
	uid, err := sm.CreateFolder(co, "new_folder", nil)
}
```

### フォルダの更新 <a href="#update-a-folder" id="update-a-folder"></a>

フォルダのメタデータ (現在はフォルダ名のみ) を更新します。

```go
UpdateFolder(folderUid, folderName string, folders []*KeeperFolder) (err error)
```

<table><thead><tr><th width="209.85161529417937">パラメータ</th><th width="206.99431983802478">型</th><th width="150">必須</th><th>説明</th></tr></thead><tbody><tr><td><code>folderUid</code></td><td><code>string</code></td><td>はい</td><td>フォルダのUID</td></tr><tr><td><code>folderName</code></td><td><code>string</code></td><td>はい</td><td>新しいフォルダ名</td></tr><tr><td><code>folders</code></td><td><code>[]*KeeperFolder</code></td><td>いいえ</td><td>親フォルダの検索に使用するフォルダのリスト</td></tr></tbody></table>

**使用例**

```go
package main

import ksm "github.com/keeper-security/secrets-manager-go/core"

func main() {
	options := &ksm.ClientOptions{Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
	sm := ksm.NewSecretsManager(options)

	err := sm.UpdateFolder("[FOLDER_UID]", "new_folder_name", nil)
}
```

### フォルダの削除 <a href="#delete-folders" id="delete-folders"></a>

フォルダのリストを削除します。空でないフォルダを削除するときは、`forceDeletion` フラグを使います。

{% hint style="info" %}
`forceDeletion` を使う場合、親フォルダと子フォルダのUIDを1つのリストにまとめて送らないでください。削除順によってはエラーになることがあります (例: 親が子より先に強制削除された場合)。リストが常にFIFO順で処理される保証はありません。
{% endhint %}

{% hint style="info" %}
ボルトに存在しないフォルダのUID、またはKSMアプリケーションに共有されていないフォルダのUIDであっても、エラーにはなりません。
{% endhint %}

<pre class="language-go"><code class="lang-go"><strong>DeleteFolder(folderUids []string, forceDeletion bool) (statuses map[string]string, err error)
</strong></code></pre>

<table><thead><tr><th width="209.85161529417937">パラメータ</th><th width="206.99431983802478">型</th><th width="150">必須</th><th>説明</th></tr></thead><tbody><tr><td><code>folderUids</code></td><td><code>[]string</code></td><td>はい</td><td>削除するフォルダのUID</td></tr><tr><td><code>forceDeletion</code></td><td><code>bool</code></td><td>いいえ</td><td>空でないフォルダを削除するには <code>true</code></td></tr></tbody></table>

**使用例**

```go
package main

import (
  "fmt"
  ksm "github.com/keeper-security/secrets-manager-go/core"
)

func main() {
  options := &ksm.ClientOptions{Config: ksm.NewFileKeyValueStorage("ksm-config.json")}
  sm := ksm.NewSecretsManager(options)

  stats, err := sm.DeleteFolder([]string{"[FOLDER_UID1]", "[FOLDER_UID2]"}, true)
  if err != nil {
    fmt.Printf("Error: %v\n", err)
    return
  }

  fmt.Printf("Deleted %d folder(s)\n", len(stats))
}
```

## 高度な構成 <a href="#advanced-configuration" id="advanced-configuration"></a>

### トークンのリージョンプレフィックス

トークンにリージョンプレフィックスが含まれている場合、接続先のKeeperデータセンターが自動的に選ばれます。

| リージョンコード | データセンター             | ホスト名                         |
| -------- | ------------------- | ---------------------------- |
| `US`     | United States       | `keepersecurity.com`         |
| `EU`     | Europe              | `keepersecurity.eu`          |
| `AU`     | Australia           | `keepersecurity.com.au`      |
| `GOV`    | US Government Cloud | `govcloud.keepersecurity.us` |
| `JP`     | Japan               | `keepersecurity.jp`          |
| `CA`     | Canada              | `keepersecurity.ca`          |

**トークンの例**

```
US:KBChlYeZ15wLzvhLVXmT61euw0DJO0cTVfkD-b-qesw
EU:JhGxK92pLmNqR5TvWx3YzAbC8dEfGhI0jKlMnOpQrSt
```

SDKはリージョンプレフィックスから接続先を判断します。プレフィックスがない場合は、`ClientOptions` の `Hostname` を明示的に指定する必要があります。

### HTTPプロキシ構成

Go SDKは、標準の環境変数からプロキシ設定を自動検出します。

**環境変数**

SDKは以下の順で環境変数を確認します。

1. `HTTPS_PROXY` または `https_proxy` - HTTPS向けに推奨
2. `HTTP_PROXY` または `http_proxy` - フォールバック用プロキシ
3. `NO_PROXY` または `no_proxy` - プロキシを使わないホストのカンマ区切りリスト

**例**

```bash
export HTTPS_PROXY=http://proxy.company.com:8080
export HTTP_PROXY=http://proxy.company.com:8080
```

認証付きプロキシ:

```bash
export HTTPS_PROXY=http://username:password@proxy.company.com:8080
```

バイパスリスト付き:

```bash
export HTTPS_PROXY=http://proxy.company.com:8080
export NO_PROXY=localhost,127.0.0.1,.internal.company.com
```

```go
import (
    "os"
    ksm "github.com/keeper-security/secrets-manager-go/core"
)

func main() {
    os.Setenv("HTTPS_PROXY", "http://proxy.company.com:8080")

    clientOptions := &ksm.ClientOptions{
        Token:  "US:[One Time Access Token]",
        Config: ksm.NewFileKeyValueStorage("ksm-config.json"),
    }
    sm := ksm.NewSecretsManager(clientOptions)

    records, err := sm.GetSecrets([]string{})
    if err != nil {
        // エラー処理
    }
}
```

{% hint style="warning" %}
**認証情報の特殊文字**: ユーザー名とパスワードに含まれる特殊文字はパーセントエンコーディングでURLエンコードします (例: `@` は `%40`、`!` は `%21`)。
{% endhint %}

### `KSM_CONFIG` 環境変数

CI/CDやコンテナ環境では、`ClientOptions` に `Config` を渡さない場合、SDKは `KSM_CONFIG` 環境変数から構成を自動読み込みします。

初回の端末バインド後に生成したJSON構成をBase64で設定します。

```bash
export KSM_CONFIG="<base64-encoded config JSON>"
```

```go
sm := ksm.NewSecretsManager(&ksm.ClientOptions{})
```

{% hint style="info" %}
既存の `ksm-config.json` からBase64値を生成する例です。

```bash
base64 -w 0 ksm-config.json
```

{% endhint %}

{% hint style="warning" %}
`KSM_CONFIG` は `ClientOptions.Config` が `nil` のときだけ読み込まれます。`Config` を明示的に渡すと、環境変数は無視されます。
{% endhint %}

### 構成ファイルのセキュリティ

`NewFileKeyValueStorage()` を使うと、SDKは自動的に以下を行います。

1. **新規構成ファイル**を権限 `0600` (所有者のみ読み書き) で作成
2. **アクセスを所有者に限定**し、他ユーザーからの参照を防ぐ
3. **暗号化キー**とデバイストークンを安全に保存

**権限の確認**

```bash
$ ls -l ksm-config.json
-rw------- 1 user user 1234 Dec 26 10:00 ksm-config.json
```

`rw-------` (0600) により、構成ファイルは所有者だけが読み書きできます。

**セキュリティ上の推奨事項**

* 構成ファイルをバージョン管理にコミットしない (`.gitignore` に `*.json` を追加)
* 開発・ステージング・本番で別の構成を使う
* ワンタイムアクセストークンは90日ごとにローテーション
* 構成ファイルは安全で暗号化されたディレクトリに保存

### エラー処理

{% hint style="info" %}
**v1.7.0で改善**: HTTPエラーは `*core.KeeperHTTPError` 型で返り、`StatusCode`、`ResultCode`、`Message` フィールドを持ちます。文字列を解析する代わりに `errors.As` で扱えます。エラーメッセージ文字列には、すべてのパスでHTTPステータスコードが一貫して含まれます。
{% endhint %}

**よくあるHTTPステータスコード**

| ステータスコード | エラー種別                 | 推奨アクション                    |
| -------- | --------------------- | -------------------------- |
| `401`    | Unauthorized          | 新しいワンタイムトークンで再初期化          |
| `403`    | Forbidden             | シークレットマネージャーでアプリケーション権限を確認 |
| `404`    | Not Found             | UIDが正しくアクセス可能か確認           |
| `429`    | Too Many Requests     | 指数バックオフで再試行                |
| `500`    | Internal Server Error | 指数バックオフで再試行                |
| `503`    | Service Unavailable   | しばらく待ってから再試行               |

{% hint style="warning" %}
**v1.7.0の破壊的変更: 復号失敗時の `nil` 返却**

以下の関数は、復号に失敗した場合に空のスタブではなく `nil` を返すようになりました。

* レコード鍵またはレコードデータの復号に失敗したときの `NewRecordFromJson`
* フォルダ復号に失敗したときの `NewFolderFromJson` / `NewKeeperFolder`
* ファイル鍵の復号に失敗したときの `NewKeeperFileFromJson`

また、直後のバインドフローでアプリ鍵の復号に失敗した場合、`GetSecrets` は空リストと `nil` エラーではなくエラーを返します。

これらの関数を直接呼ぶ場合は、戻り値をデリファレンスする前に `nil` チェックを追加してください。
{% endhint %}

{% hint style="warning" %}
**v1.7.0の破壊的変更: HTTPエラー文字列の形式**

JSONエラー応答のエラー文字列には `HTTPStatus=N` プレフィックスが付くようになりました (例: `POST Error: HTTPStatus=403 Error: access_denied, message=...`)。以前のJSONエラーパスではステータスコードが文字列に含まれませんでした。文字列を解析している呼び出し側は、`errors.As(err, &khe)` へ移行し、`khe.StatusCode`、`khe.ResultCode`、`khe.Message` をコードから直接取得してください。
{% endhint %}

#### 型付きHTTPエラー

`GetSecrets` および関連呼び出しからのHTTPエラーはすべて `*core.KeeperHTTPError` として返ります。文字列を解析する代わりに `errors.As` で構造化情報を取り出します。

```go
type KeeperHTTPError struct {
    StatusCode int
    ResultCode string
    Message    string
    Body       []byte
}
```

`GetSecrets` から返ると、呼び出し側には `POST Error: HTTPStatus=403 Error: access_denied, message=...` のように見えます。

**基本的なエラー処理**

```go
records, err := sm.GetSecrets([]string{"UID1", "UID2"})
if err != nil {
    fmt.Printf("Error retrieving secrets: %v\n", err)
    return
}
```

**特定のHTTPステータスを判定**

```go
import (
    "errors"
    "fmt"
    ksm "github.com/keeper-security/secrets-manager-go/core"
)

records, err := sm.GetSecrets([]string{"UID1"})
if err != nil {
    var khe *ksm.KeeperHTTPError
    if errors.As(err, &khe) {
        switch khe.StatusCode {
        case 401:
            fmt.Println("Authentication failed. Please re-initialize with a new token.")
        case 403:
            fmt.Printf("Access denied (%s). Check application permissions in Secrets Manager.\n", khe.ResultCode)
        case 404:
            fmt.Println("Record not found. Verify the UID is correct.")
        case 429:
            fmt.Println("Rate limit exceeded. Retrying with exponential backoff...")
        default:
            fmt.Printf("HTTP %d (%s): %s\n", khe.StatusCode, khe.ResultCode, khe.Message)
        }
        return
    }
    fmt.Printf("Unexpected error: %v\n", err)
    return
}
```

**破損レコードの扱い**

{% hint style="info" %}
**v1.7.0の耐性強化**: レコード・ファイル・フォルダで暗号化が破損している場合でも、SDKは全体を失敗させずに処理を続けます。
{% endhint %}

* **破損したレコード**は警告を出してスキップ
* **破損したファイル**はファイル一覧から除外
* **破損したフォルダ**は全体失敗を引き起こさないように処理
* **有効なレコード**は引き続き正常に返却

```go
records, err := sm.GetSecrets([]string{})
if err != nil {
    fmt.Printf("Error: %v\n", err)
    return
}

fmt.Printf("Retrieved %d accessible records\n", len(records))
```


---

# Agent Instructions: 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:

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

The question should be specific, self-contained, and written in natural language.
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.
