# 시크릿

> 토큰이 리포에도, 설정 파일에도 평문으로 남지 않는 방법입니다.

## 원칙

aisync는 토큰을 두 곳 어디에도 평문으로 쓰지 않습니다.

- **리포**: 토큰은 `secrets.json`에 암호문으로만 있고, 설정에는 `{{secret:이름}}` 참조만 남습니다.
- **이 컴퓨터의 설정 파일**: `.claude.json`에도 참조만 씁니다. 실제 값은 MCP 서버가 실행될 때 그 프로세스에만 건넵니다.

## 암호화 저장소

`secrets.json`은 패스프레이즈로 암호화합니다.

- 키: PBKDF2-SHA256(60만 회)으로 패스프레이즈에서 만듭니다.
- 암호화: AES-256-GCM. 항목마다 따로 암호화하고, 항목 이름에 묶어 다른 이름으로 옮겨 붙여도 풀리지 않습니다.
- 키는 컴퓨터마다 한 번 만들어 macOS 키체인에 둡니다. Linux에서는 `~/.config/aisync/keys`에 권한 0600 파일로 둡니다.

리포가 유출되더라도 패스프레이즈 없이는 토큰을 볼 수 없습니다. 다만 패스프레이즈가 짧으면 시간을 들여 맞혀 볼 수 있으니 길게 정하세요.

## MCP 서버가 토큰을 받는 방법

받기를 하면 aisync는 토큰을 풀어서 쓰지 않고, 서버 정의를 이렇게 바꿔 씁니다.

명령으로 실행하는 서버는 `aisync exec`로 감쌉니다.

```json
"slack": {
  "command": "/Users/you/.local/bin/aisync",
  "args": ["exec", "--repo", "you/aisync-config", "--", "npx", "-y", "@modelcontextprotocol/server-slack"],
  "env": { "SLACK_BOT_TOKEN": "{{secret:slack-bot}}" }
}
```

Claude Code가 이 서버를 띄우면 aisync가 참조를 풀어 원래 명령을 실행합니다. 값은 그 서버 프로세스에만 있습니다.

헤더로 인증하는 HTTP 서버에는 Claude Code의 `headersHelper`를 씁니다.

```json
"github": {
  "type": "http",
  "url": "https://api.githubcopilot.com/mcp/",
  "headersHelper": "/Users/you/.local/bin/aisync headers --repo you/aisync-config 'Authorization=Bearer {{secret:github-auth}}'"
}
```

Claude Code가 연결할 때마다 이 명령을 실행해 헤더를 받습니다.

`aisync exec`와 `aisync headers`는 네트워크를 쓰지 않습니다. 받기를 할 때 내려받아 둔 `secrets.json` 사본(암호문 그대로)과 키체인의 키만 씁니다.

## 토큰이 URL 안에 있으면

`https://…/mcp?token=…`처럼 URL에 토큰이 들어간 서버는 평문 없이 처리할 방법이 없어서 받아들이지 않습니다. 헤더로 인증하도록 바꾸거나, `capture --server`로 그 서버를 빼고 올리세요.

## 파일 안의 토큰(BLOCKS)

settings.json, CLAUDE.md, 스킬 파일은 있는 그대로 올라갑니다. 그래서 그 안에 토큰이 보이면 올리기를 멈춥니다.

settings.json의 `env`에 둔 토큰은 Claude Code가 다른 통로로 받을 방법이 없습니다. 두 가지 중 하나를 고르세요.

- 그 토큰이 MCP 서버용이라면 서버의 `env`로 옮깁니다. 그러면 암호화 대상이 됩니다.
- Claude 전체에 필요한 환경변수라면 settings.json에서 지우고 프로필의 `profile.json`에 `"env": {"이름": "{{secret:이름}}"}`로 둔 뒤 `aisync run <프로필>`로 Claude를 띄웁니다. 이 경우 Claude와 Claude가 실행하는 명령 모두 그 값을 볼 수 있습니다.

## 토큰 관리

```sh
aisync secret list                 # 이름만 보여 줍니다
aisync secret set github-token     # 값은 입력받거나 표준 입력에서 읽습니다
aisync secret rm github-token
aisync secret prune --dry-run      # 어느 프로필도 쓰지 않는 토큰
aisync passwd                      # 패스프레이즈 바꾸기
aisync unlock                      # 이 컴퓨터에서 패스프레이즈 다시 입력
```

`passwd`로 패스프레이즈를 바꾸면 저장소 전체를 새로 암호화합니다. 다른 컴퓨터는 다음에 리포를 받은 뒤 `aisync unlock`을 한 번 해야 MCP 서버가 다시 뜹니다.

## scan이 찾는 것

알려진 형식(Slack `xoxb-`, GitHub `ghp_`·`github_pat_`, OpenAI·Anthropic `sk-`, Vault `hvs.`, AWS `AKIA` 등)과, 이름에 TOKEN·SECRET·KEY·PASSWORD·AUTH가 들어간 값 중 무작위 문자열처럼 보이는 것을 찾습니다. 규칙 기반이라 새로운 형식은 놓칠 수 있습니다. 올리기 전에 scan 결과를 한 번 읽어 보세요.

Claude Code는 `~/.claude/backups/`에 `.claude.json` 백업을 몇 개 남겨 둡니다. 여기에는 aisync를 쓰기 전의 평문 토큰이 남아 있을 수 있고, scan이 `local`로 알려 줍니다. 오래된 백업은 Claude Code가 돌려 가며 지웁니다.
