From 1395a781826a427b23224e27e51597a98d357ee7 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Fri, 16 Oct 2026 23:13:17 +0800 Subject: [PATCH 1/2] docs: bilingual README (en + zh-CN) --- README.md | 91 ++++++++++++++++++++++++++++++++++--------------- README.zh-CN.md | 80 ++++++++++++++++++++++++++++--------------- 2 files changed, 117 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 34f47db..62858b1 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,89 @@ # SchwabTokenAutoRefresher -[Chinese README](README.zh-CN.md) +A scheduled utility that refreshes the Charles Schwab OAuth token and stores it in Google Cloud Secret Manager. -SchwabTokenAutoRefresher is a QuantStrategyLab credential automation utility. It runs the Schwab OAuth token refresh flow on a schedule and syncs the refreshed credentials to Google Cloud Secret Manager, so other platform services always have a valid token without manual renewal. It supports the system but does not decide which strategy should go live: strategy eligibility stays with the strategy and snapshot repositories, and broker execution stays with the platform repositories. +English | [简体中文](README.zh-CN.md) -> Investing involves risk. This project does not provide investment advice and is for education, research, and engineering review only. +## Status -## Design boundary +Experimental. Use at your own risk. This project is not financial advice and +does not guarantee any trading result. It handles broker credentials on behalf +of other services, so a misconfiguration can stop those services from +authenticating. It does not place orders. -- Keep contracts stable and versioned where downstream repositories depend on them. -- Prefer backward-compatible changes unless a coordinated migration is planned. -- Keep secrets and environment-specific settings outside the shared library code. -- Document changes that affect multiple platforms or strategy packages. +## What this is -## Repository layout +SchwabTokenAutoRefresher refreshes a Charles Schwab OAuth token on a schedule +and writes the refreshed credentials to Google Cloud Secret Manager, so +dependent services keep a valid token without manual renewal. It uses Playwright +to complete the broker login, including TOTP two-factor authentication, and can +route the login through an outbound HTTP proxy. It runs on Node.js 20. + +## What this is not -- `tests/`: unit, contract, and regression tests. -- `.github/workflows/`: CI, scheduled jobs, release, or deployment workflows. +It does not place, modify, or cancel orders. It does not decide which strategies +are eligible to run. It is not a general-purpose secret manager, and it does not +replace the broker platform that consumes the token. ## Quick start +Requires Node.js 20.x and npm. + ```bash npm ci ``` -## Useful docs +The refresher reads credentials from the environment and needs a browser +session, so run it under a headless X server as the `start` script does: -- No separate `docs/` directory yet; start with this README and the workflow files. +```bash +npm start +``` -## QSL architecture role +The unit tests are plain Node scripts; they do not contact the broker: -- **Layer**: `platform-tooling`. -- **Responsibility**: Schwab OAuth token refresh automation utility. -- **Owns**: token refresh flow and Secret Manager sync behavior. -- **Consumes**: Schwab auth endpoints, Google Secret Manager, CharlesSchwabPlatform. -- **Must not**: decide strategy eligibility or log sensitive token values. +```bash +node tests/test_auth_retry.js +node tests/test_proxy_config.js +node tests/test_auth_code_extraction.js +``` + +## Configuration + +| Variable | Required | Default | Purpose | +|---|---|---|---| +| `SCHWAB_USERNAME` | Yes | none | Broker login name. | +| `SCHWAB_PASSWORD` | Yes | none | Broker login password. | +| `SCHWAB_TOTP_SECRET` | Yes | none | Base32 secret used to generate TOTP codes. | +| `SCHWAB_API_KEY` | Yes | none | OAuth application key. | +| `SCHWAB_APP_SECRET` | Yes | none | OAuth application secret. | +| `SCHWAB_REDIRECT_URI` | Yes | none | OAuth redirect URI registered with the application. | +| `GCP_PROJECT_ID` | Yes | none | Google Cloud project that holds the secret. | +| `GCP_SECRET_ID` | Yes | none | Secret Manager secret to update. | +| `GCP_SA_KEY` | No | ambient credentials | Service account key JSON when ambient credentials are not available. | +| `GCP_SECRET_VERSION_RETENTION` | No | `1` | Number of secret versions to keep; older versions are disabled. | +| `SCHWAB_PROXY_URL` | No | none | HTTP proxy for the login flow. | +| `SCHWAB_FORCE_PROXY_FIRST` | No | disabled | Use the proxy before a direct connection when set to `true`. | + +## Repository layout + +``` +main.js scheduled refresh entrypoint +lib/ proxy, OAuth, and retry helpers +tests/ dependency-free unit tests +prompts/ review prompt text +scripts/ operator helpers +``` -## QSL compatibility +## Contributing -- `qsl.toml` records `tier`, `upgrade_ring`, and `compat.bundle` for compatibility checks. -- This Node.js token refresh utility uses `npm` for dependency installation. +See [CONTRIBUTING.md](CONTRIBUTING.md). -## Community and security +## Security -- See [CONTRIBUTING.md](CONTRIBUTING.md) for pull request scope, local verification, and documentation expectations. -- Follow [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for maintainer and contributor conduct. -- Report credential, automation, broker, exchange, or cloud-resource vulnerabilities through [SECURITY.md](SECURITY.md); do not open public issues for secrets or live-execution risk. +See [SECURITY.md](SECURITY.md). Do not open a public issue for a vulnerability. +Never commit credentials or token material. ## License -See [LICENSE](LICENSE). +MIT. See [LICENSE](LICENSE). diff --git a/README.zh-CN.md b/README.zh-CN.md index ac1dc85..5dbfbe9 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,52 +1,78 @@ # SchwabTokenAutoRefresher -[English README](README.md) +按计划刷新 Charles Schwab OAuth token,并写入 Google Cloud Secret Manager 的工具。 -SchwabTokenAutoRefresher 是 QuantStrategyLab 的凭据自动化工具,按计划刷新 Schwab OAuth token,并把刷新后的凭据同步到 Google Cloud Secret Manager,让其他平台服务随时能拿到有效凭据,不需要人工续期。它支撑系统运行,但不决定哪个策略应该 live:策略资格由策略仓和 snapshot 仓负责,券商执行由平台仓负责。 +[English](README.md) | 简体中文 -> 投资有风险。本项目不构成投资建议,仅用于学习、研究和工程审阅。 +## 状态 -## 设计边界 +实验性项目,使用风险自负。本项目不构成投资建议,也不保证任何交易结果。它代替其他服务管理券商凭据,配置错误会导致这些服务无法完成认证。它不提交订单。 -- 下游仓库依赖的契约要保持稳定,必要时做版本化。 -- 除非有协同迁移计划,否则优先保持向后兼容。 -- 密钥和环境专属配置不要写进共享库代码。 -- 会影响多个平台或策略包的改动,需要在文档中说明。 +## 简介 -## 仓库结构 +SchwabTokenAutoRefresher 按计划刷新 Charles Schwab OAuth token,并把刷新后的凭据写入 Google Cloud Secret Manager,让依赖它的服务无需人工续期即可持有有效 token。它用 Playwright 完成券商登录,包括 TOTP 双因素认证,并支持通过出站 HTTP 代理访问。运行环境为 Node.js 20。 + +## 不适用范围 -- `tests/`:单元测试、契约测试和回归测试。 -- `.github/workflows/`:CI、定时任务、发布或部署 workflow。 +它不提交、修改或撤销订单。它不决定哪些策略可以运行。它不是通用的密钥管理服务,也不替代消费该 token 的平台仓库。 ## 快速开始 +需要 Node.js 20.x 和 npm。 + ```bash npm ci ``` -## 延伸文档 +刷新器从环境变量读取凭据,并且需要浏览器会话,因此在无显示环境下要像 `start` 脚本那样用 headless X server 运行: -- 暂无独立 `docs/` 目录;请先阅读本 README 和 workflow 文件。 +```bash +npm start +``` -## QSL 架构角色 +单元测试是普通的 Node 脚本,不会访问券商: -- **层级**:`平台工具`。 -- **职责**:Schwab OAuth token refresh 自动化工具。 -- **事实源/归属**:token refresh flow 和 Secret Manager sync 行为。 -- **消费对象**:Schwab auth endpoints、Google Secret Manager、CharlesSchwabPlatform。 -- **禁止事项**:决定策略 eligibility 或记录敏感 token 值。 +```bash +node tests/test_auth_retry.js +node tests/test_proxy_config.js +node tests/test_auth_code_extraction.js +``` + +## 配置 + +| 变量 | 必填 | 默认值 | 用途 | +|---|---|---|---| +| `SCHWAB_USERNAME` | 是 | 无 | 券商登录名。 | +| `SCHWAB_PASSWORD` | 是 | 无 | 券商登录密码。 | +| `SCHWAB_TOTP_SECRET` | 是 | 无 | 生成 TOTP 验证码的 Base32 密钥。 | +| `SCHWAB_API_KEY` | 是 | 无 | OAuth 应用 key。 | +| `SCHWAB_APP_SECRET` | 是 | 无 | OAuth 应用 secret。 | +| `SCHWAB_REDIRECT_URI` | 是 | 无 | 在应用中登记的 OAuth 回调地址。 | +| `GCP_PROJECT_ID` | 是 | 无 | 存放密钥的 Google Cloud 项目。 | +| `GCP_SECRET_ID` | 是 | 无 | 要更新的 Secret Manager 密钥。 | +| `GCP_SA_KEY` | 否 | 环境默认凭据 | 无法使用环境默认凭据时提供的 service account key JSON。 | +| `GCP_SECRET_VERSION_RETENTION` | 否 | `1` | 保留的密钥版本数量;更早的版本会被停用。 | +| `SCHWAB_PROXY_URL` | 否 | 无 | 登录流程使用的 HTTP 代理。 | +| `SCHWAB_FORCE_PROXY_FIRST` | 否 | 关闭 | 设为 `true` 时优先经代理连接,再尝试直连。 | + +## 仓库结构 + +``` +main.js 定时刷新入口 +lib/ 代理、OAuth 和重试辅助模块 +tests/ 无外部依赖的单元测试 +prompts/ 审阅提示词 +scripts/ 运维脚本 +``` -## QSL 兼容性 +## 参与贡献 -- `qsl.toml` 记录 `tier`、`upgrade_ring` 和 `compat.bundle`,用于兼容性检查。 -- 这个 Node.js token 刷新工具通过 `npm` 安装依赖。 +见 [CONTRIBUTING.md](CONTRIBUTING.md)。 -## 社区和安全 +## 安全 -- 贡献前请阅读 [CONTRIBUTING.md](CONTRIBUTING.md),确认 PR 范围、本地校验和文档要求。 -- 讨论、issue 和 review 请遵守 [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)。 -- 涉及密钥、自动化、券商/交易所或云资源的漏洞请按 [SECURITY.md](SECURITY.md) 私密报告;不要为 secret 或实盘风险开公开 issue。 +见 [SECURITY.md](SECURITY.md)。安全漏洞不要开公开 issue,也不要把凭据或 token 提交到仓库。 ## 许可证 -详见 [LICENSE](LICENSE)。 +MIT,见 [LICENSE](LICENSE)。 From 767ed4feb4ccc6b0d21faf21464e605794b89302 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Sat, 17 Oct 2026 00:31:49 +0800 Subject: [PATCH 2/2] docs: fix README review findings (en + zh-CN) --- README.md | 4 ++-- README.zh-CN.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 62858b1..97960fc 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ node tests/test_auth_code_extraction.js | `GCP_PROJECT_ID` | Yes | none | Google Cloud project that holds the secret. | | `GCP_SECRET_ID` | Yes | none | Secret Manager secret to update. | | `GCP_SA_KEY` | No | ambient credentials | Service account key JSON when ambient credentials are not available. | -| `GCP_SECRET_VERSION_RETENTION` | No | `1` | Number of secret versions to keep; older versions are disabled. | +| `GCP_SECRET_VERSION_RETENTION` | No | `1` | Number of secret versions to keep; older versions are permanently destroyed and cannot be restored. | | `SCHWAB_PROXY_URL` | No | none | HTTP proxy for the login flow. | | `SCHWAB_FORCE_PROXY_FIRST` | No | disabled | Use the proxy before a direct connection when set to `true`. | @@ -70,7 +70,7 @@ node tests/test_auth_code_extraction.js ``` main.js scheduled refresh entrypoint lib/ proxy, OAuth, and retry helpers -tests/ dependency-free unit tests +tests/ unit tests (use installed dependencies) prompts/ review prompt text scripts/ operator helpers ``` diff --git a/README.zh-CN.md b/README.zh-CN.md index 5dbfbe9..c37b92a 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -51,7 +51,7 @@ node tests/test_auth_code_extraction.js | `GCP_PROJECT_ID` | 是 | 无 | 存放密钥的 Google Cloud 项目。 | | `GCP_SECRET_ID` | 是 | 无 | 要更新的 Secret Manager 密钥。 | | `GCP_SA_KEY` | 否 | 环境默认凭据 | 无法使用环境默认凭据时提供的 service account key JSON。 | -| `GCP_SECRET_VERSION_RETENTION` | 否 | `1` | 保留的密钥版本数量;更早的版本会被停用。 | +| `GCP_SECRET_VERSION_RETENTION` | 否 | `1` | 保留的密钥版本数量;更早的版本会被永久销毁,无法恢复。 | | `SCHWAB_PROXY_URL` | 否 | 无 | 登录流程使用的 HTTP 代理。 | | `SCHWAB_FORCE_PROXY_FIRST` | 否 | 关闭 | 设为 `true` 时优先经代理连接,再尝试直连。 | @@ -60,7 +60,7 @@ node tests/test_auth_code_extraction.js ``` main.js 定时刷新入口 lib/ 代理、OAuth 和重试辅助模块 -tests/ 无外部依赖的单元测试 +tests/ 单元测试(使用已安装的依赖) prompts/ 审阅提示词 scripts/ 运维脚本 ```