policies: add standard policy files, formatting, and secret scanning

- Add .editorconfig, .prettierrc, .prettierignore, .gitignore
- Add Makefile with fmt, fmt-check, secret-scan, test (skip) targets
- Add package.json with prettier
- Add tools/secret-scan.sh
- Add .secret-scan-allowlist for documentation token format references
- Sanitize documentation to use generic placeholders
- Auto-format with prettier
- make check passes clean
This commit is contained in:
sol
2026-03-01 07:28:54 +00:00
parent 32a4e739dc
commit 0b94cb8fd5
19 changed files with 291 additions and 110 deletions

View File

@@ -4,8 +4,8 @@
Claude Max subscriptions use OAuth tokens for API authentication.
- **Access token** (`sk-ant-oat01-...`): Used for API requests, expires in ~8 hours
- **Refresh token** (`sk-ant-ort01-...`): Used to get new access tokens, long-lived
- **Access token** (`<access-token-value>`): Used for API requests, expires in ~8 hours
- **Refresh token** (`<refresh-token-value>`): Used to get new access tokens, long-lived
- **Token endpoint**: `POST https://console.anthropic.com/v1/oauth/token`
- **Client ID**: `9d1c250a-e61b-44d9-88ed-5944d1962f5e` (Claude Code public OAuth client)
@@ -25,21 +25,21 @@ The relevant function in Claude Code's minified source (`cli.js`):
```javascript
// Simplified from minified source
async function refreshToken(refreshToken, scopes) {
const params = {
grant_type: "refresh_token",
refresh_token: refreshToken,
client_id: CLIENT_ID,
scope: scopes.join(" ")
};
const response = await axios.post(TOKEN_URL, params, {
headers: { "Content-Type": "application/json" }
});
return {
accessToken: response.data.access_token,
refreshToken: response.data.refresh_token || refreshToken,
expiresAt: Date.now() + response.data.expires_in * 1000,
scopes: response.data.scope.split(" ")
};
const params = {
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: CLIENT_ID,
scope: scopes.join(' '),
};
const response = await axios.post(TOKEN_URL, params, {
headers: { 'Content-Type': 'application/json' },
});
return {
accessToken: response.data.access_token,
refreshToken: response.data.refresh_token || refreshToken,
expiresAt: Date.now() + response.data.expires_in * 1000,
scopes: response.data.scope.split(' '),
};
}
```
@@ -65,6 +65,7 @@ inotifywait -q -e close_write,moved_to "$WATCH_DIR"
- We watch the **directory** not the file, because atomic renames create a new inode
When the file changes:
1. Read `accessToken`, `refreshToken`, `expiresAt` from Claude CLI format
2. Map fields: `accessToken` -> `access`, `refreshToken` -> `refresh`, `expiresAt` -> `expires`
3. Write to `oauth.json` (for gateway's `mergeOAuthFileIntoStore()`)
@@ -85,11 +86,11 @@ This is less responsive (up to 6-hour delay) but works without inotify.
## Field Mapping
| Claude CLI (`.credentials.json`) | OpenClaw (`oauth.json`) |
|----------------------------------|------------------------|
| `claudeAiOauth.accessToken` | `anthropic.access` |
| `claudeAiOauth.refreshToken` | `anthropic.refresh` |
| `claudeAiOauth.expiresAt` | `anthropic.expires` |
| `claudeAiOauth.scopes` | `anthropic.scopes` |
| -------------------------------- | ----------------------- |
| `claudeAiOauth.accessToken` | `anthropic.access` |
| `claudeAiOauth.refreshToken` | `anthropic.refresh` |
| `claudeAiOauth.expiresAt` | `anthropic.expires` |
| `claudeAiOauth.scopes` | `anthropic.scopes` |
## Timeline