init
This commit is contained in:
34
specs/003-hub-auth-fields/checklists/requirements.md
Normal file
34
specs/003-hub-auth-fields/checklists/requirements.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Specification Quality Checklist: Hub 配置凭证字段
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
||||
**Created**: 2025-11-14
|
||||
**Feature**: [spec.md](../spec.md)
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] No implementation details (languages, frameworks, APIs)
|
||||
- [x] Focused on user value and business needs
|
||||
- [x] Written for non-technical stakeholders
|
||||
- [x] All mandatory sections completed
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [x] No [NEEDS CLARIFICATION] markers remain
|
||||
- [x] Requirements are testable and unambiguous
|
||||
- [x] Success criteria are measurable
|
||||
- [x] Success criteria are technology-agnostic (no implementation details)
|
||||
- [x] All acceptance scenarios are defined
|
||||
- [x] Edge cases are identified
|
||||
- [x] Scope is clearly bounded
|
||||
- [x] Dependencies and assumptions identified
|
||||
|
||||
## Feature Readiness
|
||||
|
||||
- [x] All functional requirements have clear acceptance criteria
|
||||
- [x] User scenarios cover primary flows
|
||||
- [x] Feature meets measurable outcomes defined in Success Criteria
|
||||
- [x] No implementation details leak into specification
|
||||
|
||||
## Notes
|
||||
|
||||
- Items marked incomplete require spec updates before `/speckit.clarify` or `/speckit.plan`
|
||||
31
specs/003-hub-auth-fields/contracts/config-schema.md
Normal file
31
specs/003-hub-auth-fields/contracts/config-schema.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Config Schema Contract
|
||||
|
||||
```toml
|
||||
# Global section
|
||||
ListenPort = 5000
|
||||
LogLevel = "info"
|
||||
StoragePath = "./storage"
|
||||
CacheTTL = 86400
|
||||
# ... existing global keys ...
|
||||
|
||||
[[Hub]]
|
||||
Name = "docker"
|
||||
Domain = "docker.hub.local"
|
||||
Upstream = "https://registry-1.docker.io"
|
||||
Proxy = ""
|
||||
Username = "" # optional
|
||||
Password = "" # optional
|
||||
Type = "docker" # required, must be docker|npm|go
|
||||
CacheTTL = 43200 # optional override
|
||||
```
|
||||
```
|
||||
|
||||
| Field | Required | Type | Notes |
|
||||
|----------------------|----------|---------|-------|
|
||||
| `ListenPort` | Yes | int | 单端口监听,范围 1-65535 |
|
||||
| `Username`/`Password`| No | string | 缺省表示匿名;若任一非空则视为 credentialed,日志仅显示掩码 |
|
||||
| `Type` | Yes | enum | 当前支持 `docker`/`npm`/`go`,输入其他值时报错 |
|
||||
|
||||
**Validation Contract**
|
||||
1. `any-hub --check-config` 必须在缺失 `Type` 或非法 `ListenPort` 时返回非 0。
|
||||
2. CLI 日志需输出 `hub_type` 与 `auth_mode` 字段,以便运维确认配置是否生效。
|
||||
33
specs/003-hub-auth-fields/data-model.md
Normal file
33
specs/003-hub-auth-fields/data-model.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Data Model: Hub 配置凭证字段
|
||||
|
||||
## HubConfig
|
||||
- **Fields**:
|
||||
- `Name` (string, required, unique)
|
||||
- `Domain` (string, required, Host header used for路由)
|
||||
- `Upstream` (URL, required)
|
||||
- `Proxy` (URL, optional)
|
||||
- `Username` (string, optional, may be empty)
|
||||
- `Password` (string, optional, may be empty)
|
||||
- `Type` (enum: docker | npm | go, required)
|
||||
- `CacheTTL` (duration override, optional)
|
||||
- **Relationships**: 属于全局 `Config`,在运行期被 `HubRegistry` 索引。
|
||||
- **Validation**: `Username` 与 `Password` 要么同时缺省要么同时提供;`Type` 仅允许受支持的值。
|
||||
|
||||
## GlobalConfig
|
||||
- **Fields**:
|
||||
- `ListenPort` (int, required, 1-65535)
|
||||
- 现有全局字段(LogLevel、StoragePath、CacheTTL、MaxRetries 等)保持不变
|
||||
- **Relationships**: CLI 仅在 `ListenPort` 启动一次 Fiber 服务;HubRegistry 使用该端口验证 Host:port。
|
||||
|
||||
## AuthProfile (runtime)
|
||||
- **Fields**:
|
||||
- `HubName`
|
||||
- `AuthMode` (anonymous | credentialed)
|
||||
- `LastAttempt` timestamp
|
||||
- `Status` (success | failed)
|
||||
- **Purpose**: 供日志/metrics 输出,帮助追踪凭证是否生效。
|
||||
- **State transitions**: anonymous→credentialed 当检测到配置凭证;credentialed→anonymous 当凭证校验失败且被禁用(未来扩展)。
|
||||
|
||||
## HubType (enum)
|
||||
- **Values**: docker, npm, go(后续 apt/yum/composer 等)
|
||||
- **Usage**: 决定请求头/日志字段/未来仓库特定策略;存储于 HubConfig。
|
||||
69
specs/003-hub-auth-fields/plan.md
Normal file
69
specs/003-hub-auth-fields/plan.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# Implementation Plan: Hub 配置凭证字段
|
||||
|
||||
**Branch**: `003-hub-auth-fields` | **Date**: 2025-11-14 | **Spec**: [/home/rogee/Projects/any-hub/specs/003-hub-auth-fields/spec.md](./spec.md)
|
||||
**Input**: Feature specification from `/specs/003-hub-auth-fields/spec.md`
|
||||
|
||||
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/commands/plan.md` for the execution workflow.
|
||||
|
||||
## Summary
|
||||
|
||||
交付单端口 Host 路由代理的配置增强:
|
||||
1. 将监听端口提升到全局 `ListenPort` 字段,所有 Hub 共享同一 Fiber 端口并严格依赖 Host 头;旧的 `[[Hub]].Port` 需在配置校验阶段报错并提供迁移指引。
|
||||
2. 为 Hub 添加可选 `Username`/`Password` 字段,由 CLI 在回源时自动注入 Authorization header,同时在日志中只暴露掩码。
|
||||
3. 为 Hub 添加必填 `Type` 枚举(当前支持 docker/npm/go),驱动日志字段与未来协议特定策略,并保留扩展钩子。
|
||||
4. 更新示例配置、quickstart、文档与测试,确保凭证/类型/单端口行为可独立验证。
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: Go 1.25+(静态链接单二进制)
|
||||
**Primary Dependencies**: Fiber v3(HTTP 服务)、Viper(配置加载/校验)、Logrus + Lumberjack(结构化日志 & 滚动)、标准库 `net/http`/`io`(代理回源)
|
||||
**Storage**: 本地 `StoragePath/<Hub>/<path>` + `.meta` 元数据缓存布局
|
||||
**Testing**: `GOCACHE=/tmp/go-build go test ./...`,基于 `httptest` + upstream stub + 临时目录验证配置、代理、缓存、Host 路由
|
||||
**Target Platform**: Linux/Unix CLI 进程,由 systemd/supervisor 管理,匿名下游客户端
|
||||
**Project Type**: 单 Go 模块(`cmd/any-hub` 入口 + `internal/config|server|cache|proxy`)
|
||||
**Performance Goals**: 回源路径仍需流式复制并保持单请求 <256MB;凭证注入不可降低缓存命中率;单端口模式吞吐与现状持平
|
||||
**Constraints**: 禁止新增依赖;所有行为受单一 `config.toml` 控制;凭证不得写入日志;需提供向后兼容的迁移提示
|
||||
**Scale/Scope**: 当前支持 docker/npm/go 三类仓库,未来可扩展 apt/yum/composer/go proxy 等;单端口 Host 路由需支撑数十 Hub 并保持透明体验
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
- 方案继续服务“轻量 CLI 多仓代理”使命,未引入 UI/账号体系或附加系统。
|
||||
- 仍使用 Go + Fiber/Viper/Logrus/Lumberjack/标准库,无新增依赖。
|
||||
- 所有新增能力均由 `config.toml` 驱动,且设计了默认值/校验/迁移提示。
|
||||
- 缓存优先 + 流式回源路径保持不变;凭证注入仅影响上游请求头。
|
||||
- 计划列出了配置解析、代理凭证、Host 路由等必备测试,并要求中文注释与 quickstart 更新。
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/003-hub-auth-fields/
|
||||
├── plan.md # 当前文件
|
||||
├── research.md # Phase 0 输出
|
||||
├── data-model.md # Phase 1 输出
|
||||
├── quickstart.md # Phase 1 输出
|
||||
├── contracts/ # Phase 1 输出
|
||||
└── tasks.md # Phase 2 输出(由 /speckit.tasks 生成)
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
```text
|
||||
cmd/any-hub/main.go # CLI 入口、单端口监听
|
||||
internal/config/ # TOML schema + 校验 + 默认值
|
||||
internal/server/ # Host Registry、Fiber 启动
|
||||
internal/cache/ # 缓存方案(需保持兼容)
|
||||
internal/proxy/ # 凭证注入、类型策略、流式代理
|
||||
configs/ # 示例 config(docker/npm/go)
|
||||
tests/ # 单元/集成测试 (httptest、stubs)
|
||||
```
|
||||
|
||||
**Structure Decision**: 延续既有模块划分;单端口逻辑集中在 `internal/server`,凭证/类型侧重 `internal/config` + `internal/proxy`,必要时可新增 `internal/server/types` 等子包但需保持依赖有向无环。
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
||||
|-----------|------------|-------------------------------------|
|
||||
| _None_ | — | — |
|
||||
52
specs/003-hub-auth-fields/quickstart.md
Normal file
52
specs/003-hub-auth-fields/quickstart.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Quickstart: Hub 凭证与类型配置
|
||||
|
||||
## 前置检查
|
||||
|
||||
| 字段 | 说明 | 验证方式 |
|
||||
|------|------|----------|
|
||||
| `ListenPort` | 全局唯一监听端口,所有 Hub 共用 | `any-hub --check-config` 会输出 `listen_port=<port>` |
|
||||
| `Username`/`Password` | 可选凭证字段,两个字段必须同时出现 | 成功日志含 `auth_mode=credentialed`;缺失时为 `anonymous` |
|
||||
| `Type` | 仓库类型,当前支持 `docker`/`npm`/`go` | 错误输入将导致 `hub_type_invalid` 报错 |
|
||||
|
||||
**基本命令**
|
||||
|
||||
```bash
|
||||
any-hub --check-config --config hub-auth.toml
|
||||
any-hub --config hub-auth.toml
|
||||
```
|
||||
|
||||
1. **准备配置**
|
||||
```bash
|
||||
cp configs/config.example.toml hub-auth.toml
|
||||
```
|
||||
- 在全局段添加 `ListenPort = 5000` 并移除 `[[Hub]]` 中的 `Port` 字段。
|
||||
- 为需要解锁 rate-limit 的 Hub 写入 `Username`/`Password`,保持小写字符串。
|
||||
- 设置 `Type` 为 `docker`、`npm` 或 `go`。其它值会被 `any-hub --check-config` 拒绝,并在日志中提示 `hub_type_unsupported`。若需扩展新的仓库类型,请遵循 plan.md 中的“类型扩展策略”提交补丁。
|
||||
|
||||
2. **运行校验**
|
||||
```bash
|
||||
any-hub --check-config --config hub-auth.toml
|
||||
```
|
||||
预期日志:`{"action":"check_config","credentials":["docker:credentialed"],"listen_port":5000,"result":"ok"}`(无凭证的 Hub 会显示 `hub:anonymous`)。
|
||||
|
||||
3. **启动代理**
|
||||
```bash
|
||||
any-hub --config hub-auth.toml
|
||||
```
|
||||
CLI 只监听 `ListenPort` 指定的端口,所有 Hub 通过 Host 头路由。
|
||||
|
||||
4. **验证凭证透传**
|
||||
```bash
|
||||
# Docker CLI 方式
|
||||
curl -H "Host: docker.hub.local" http://127.0.0.1:5000/v2/
|
||||
|
||||
# NPM 方式(匿名客户端,不需要 .npmrc 凭证)
|
||||
npm --registry http://127.0.0.1:5000 --always-auth=false view lodash
|
||||
```
|
||||
- 代理会在回源请求中自动注入 `Username`/`Password`,而下游 `curl`/`npm` 无须提供任何 Authorization header。
|
||||
|
||||
5. **观察日志**
|
||||
- 每条请求日志包含 `hub`, `hub_type`, `auth_mode`, `upstream_status`。
|
||||
- 若凭证无效,会出现 `error=auth_failed`,需更新配置并重启。
|
||||
- `config.toml` 保存明文凭证,部署时请配合 `chmod 600` 或密钥注入工具限制读取范围。
|
||||
- 建议执行 `tail -n 20 logs/any-hub.log | jq '.auth_mode,.hub_type,.cache_hit'`,确认命中缓存与凭证状态。
|
||||
22
specs/003-hub-auth-fields/research.md
Normal file
22
specs/003-hub-auth-fields/research.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Research: Hub 配置凭证字段
|
||||
|
||||
## Credential Handling in config.toml
|
||||
- **Decision**: 允许在 `[[Hub]]` 中以明文写入 `Username`/`Password`,CLI 读取后立即掩码写日志,并鼓励与外部 Secret 管理(环境变量/Ansible Vault)组合。
|
||||
- **Rationale**: 代理以 CLI 形式部署,最简单可靠的方式是继续沿用 TOML;通过 `config --check-config` 校验与日志掩码即可满足大多数场景。
|
||||
- **Alternatives considered**:
|
||||
- 单独的凭证文件:需要额外路径与权限管理,易造成部署复杂化。
|
||||
- 环境变量注入:缺乏结构化校验,且与当前 TOML 驱动原则冲突。
|
||||
|
||||
## Hub Type 枚举与扩展
|
||||
- **Decision**: 首批仅支持 `docker`、`npm`、`go`,在 `internal/config` 中实现枚举校验,并在 `internal/proxy`/`internal/server` 中通过 `switch type` 执行类型特定逻辑;保留 `default` 分支抛出“未支持类型”错误,为 apt/yum/composer 等新增项预留 hook。
|
||||
- **Rationale**: 明确 types 可让日志/策略按仓库协议定制,同时使用枚举校验可避免错误输入;`switch` + 独立 helper 便于未来拆分成策略表。
|
||||
- **Alternatives considered**:
|
||||
- 自定义字符串+运行期反射:增加复杂度且容易出错。
|
||||
- 大型插件机制:当前范围只需声明式扩展,无需插件框架。
|
||||
|
||||
## 单端口 Host 路由迁移
|
||||
- **Decision**: 将监听端口移至全局(如 `ListenPort`),Fiber 仅在该端口启动一次;Hub 级 `Port` 字段在配置加载阶段报错提示迁移。路由层严格依赖 `Host`/`Host:port` 解析,必要时通过 `SERVER_PORT` 环境变量或 CLI flag override。
|
||||
- **Rationale**: 单端口可简化暴露面并符合“Host 区分仓库”的目标;在 `internal/server` 中已有 Host registry,可直接复用。
|
||||
- **Alternatives considered**:
|
||||
- 同时保留 per-Hub 端口:违背“统一端口”诉求且增加监听资源。
|
||||
- 动态多端口监听:需要额外 goroutine/生命周期管理,复杂度高。
|
||||
114
specs/003-hub-auth-fields/spec.md
Normal file
114
specs/003-hub-auth-fields/spec.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# Feature Specification: Hub 配置凭证字段
|
||||
|
||||
**Feature Branch**: `003-hub-auth-fields`
|
||||
**Created**: 2025-11-14
|
||||
**Status**: Draft
|
||||
**Input**: User description: "Hub 配置中添加 Username/Password/type类型 三个字段,user:password是为了保证上游需要认证时,下游无需认证即可获取,如docker需要登录后可以解除rate-limit;type用于指定代理的仓库类型,用于区分镜像仓库类型为不同类型的仓库进行定制化操作。当前分支名需要003开头。"
|
||||
|
||||
> 宪法对齐(v1.0.0):
|
||||
> - 保持“轻量、匿名、CLI 多仓代理”定位:不得引入 Web UI、账号体系或与代理无关的范围。
|
||||
> - 方案必须基于 Go 1.25+ 单二进制,依赖仅限 Fiber、Viper、Logrus/Lumberjack 及必要标准库。
|
||||
> - 所有行为由单一 `config.toml` 控制;若需新配置项,需在规范中说明字段、默认值与迁移策略。
|
||||
> - 设计需维护缓存优先 + 流式传输路径,并描述命中/回源/失败时的日志与观测需求。
|
||||
> - 验收必须包含配置解析、缓存读写、Host Header 绑定等测试与中文注释交付约束。
|
||||
|
||||
## Clarifications
|
||||
|
||||
### Session 2025-11-14
|
||||
|
||||
- Q: 当 `Username` 与 `Password` 只提供其中一个时应如何处理? → A: 在 `config --check-config` 阶段直接判定为配置错误,要求两个字段要么同时提供要么一起缺省。
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
<!--
|
||||
IMPORTANT: User stories should be PRIORITIZED as user journeys ordered by importance.
|
||||
Each user story/journey must be INDEPENDENTLY TESTABLE - meaning if you implement just ONE of them,
|
||||
you should still have a viable MVP (Minimum Viable Product) that delivers value.
|
||||
|
||||
Assign priorities (P1, P2, P3, etc.) to each story, where P1 is the most critical.
|
||||
Think of each story as a standalone slice of functionality that can be:
|
||||
- Developed independently
|
||||
- Tested independently
|
||||
- Deployed independently
|
||||
- Demonstrated to users independently
|
||||
-->
|
||||
|
||||
### User Story 1 - 配置上游凭证 (Priority: P1)
|
||||
|
||||
运维人员需要在 `config.toml` 中为特定 Hub 写入上游所需的 `Username`/`Password`,以便在代理启动后自动携带凭证,解除匿名拉取的速率限制或访问受保护的仓库。
|
||||
|
||||
**Why this priority**: 没有可配置的凭证字段就无法满足受限仓库或需要登录的上游,代理将丧失关键价值。
|
||||
|
||||
**Independent Test**: 仅依赖配置与 CLI 启动,即可通过加载带有不同凭证的配置文件并观察日志/校验错误来验证。
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** Hub 缺省 `Username`/`Password`,**When** CLI 读取配置,**Then** 字段可为空并保持当前匿名行为。
|
||||
2. **Given** Hub 提供 `Username=foo`、`Password=bar`,**When** CLI 运行 `--check-config`,**Then** 配置校验通过且凭证不会在日志中明文打印。
|
||||
3. **Given** Hub 配置凭证,**When** upstream 需要 Basic/Bearer 登录,**Then** 代理转发请求时自动附带凭证,终端可观察到 rate-limit 不再触发。
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - 下游透明体验 (Priority: P1)
|
||||
|
||||
下游开发者希望继续使用匿名方式访问代理,而代理应在后台代为认证;同一个代理可针对不同 Hub 自动切换凭证与仓库类型。
|
||||
|
||||
**Why this priority**: 透明体验是“单点代理”的核心卖点;若仍需下游显式登录,就无法简化 CI/CD。
|
||||
|
||||
**Independent Test**: 使用 curl/npm/docker 命令只指定 Host/端口即可验证,无需改动其他系统。
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** Hub 已配置凭证,**When** 下游客户端不带任何 Authorization header,**Then** 代理回源时自行插入 `Username`/`Password` 并返回 200 响应。
|
||||
2. **Given** 多个 Hub 配置了不同仓库类型,**When** 同一 CLI 进程同时监听多个端口,**Then** 每个端口都能在日志中打印正确的 `hub`、`type`、`auth_mode` 字段。
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - 仓库类型适配 (Priority: P2)
|
||||
|
||||
平台需要在配置中声明 `Type`(如 `docker`、`npm`、`generic-http`),以区分仓库协议并触发未来的类型特定策略(Header 处理、元数据)。
|
||||
|
||||
**Why this priority**: 明确的仓库类型是后续分支(镜像仓库 vs. 包仓库)实施自定义逻辑的前提;越早保存该字段,越容易扩展。
|
||||
|
||||
**Independent Test**: 通过配置不同的 Type 值,启动 CLI 并验证日志/metrics 中输出的类型以及针对未知类型的回退策略。
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** Hub `Type=docker`、`npm` 或 `go`,**When** 代理启动,**Then** 日志/配置校验会表明使用对应策略,非法值或缺失将被拒绝并提示可选列表。
|
||||
2. **Given** Hub 未按要求设置 `Type`,**When** CLI 运行或 `--check-config`,**Then** 返回校验错误并指明必须从受支持列表中选择(docker/npm/go,未来扩展)。
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- 当 `Username` 或 `Password` 单独出现时,系统必须在配置校验阶段阻止并提示需同时提供。
|
||||
- 当 `Type` 与实际上游协议不符(如标记为 docker 但 upstream 为 npm)时,需确保仍可 fallback 到透传并输出警告。
|
||||
- 凭证旋转:在 CLI 重启前如何避免旧凭证仍被缓存?需记录文档告知必须重启或触发热加载。
|
||||
- 凭证日志安全:所有日志中禁止打印纯文本密码,且结构化日志只显示是否启用凭证。
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: Hub 配置必须支持新增 `Username`、`Password` 字段,字段为完全可选,若未配置则保持匿名透传;若任意一项填写则必须两项同时提供(允许为空字符串),否则 `config --check-config` 需报错并拒绝启动。
|
||||
- **FR-002**: CLI 在读取配置后必须将凭证存入运行期内存,不得在 `logger` 输出中展示明文(只可显示存在性或掩码)。
|
||||
- **FR-003**: 代理回源请求必须根据 Hub 配置决定是否附加 Authorization header;缺省模式保持现状(匿名)。
|
||||
- **FR-004**: 当 upstream 返回 401/429 且 Hub 配置了凭证,系统必须重试一次(遵循既有重试策略)并记录“凭证认证失败”的错误字段,便于排障。
|
||||
- **FR-005**: Hub 配置需新增必填 `Type` 字段,短期支持值列表(`docker`, `npm`, `go`),配置校验必须拒绝缺失值或列表外值,并提示“仅支持 docker/npm/go,未来将扩展 apt/yum/composer 等”。
|
||||
- **FR-006**: CLI/日志/metrics 必须输出 `hub_type`、`auth_mode`(anonymous/credentialed)等字段,方便观察不同仓库行为,并在新增类型时无需额外字段即可扩展。
|
||||
- **FR-007**: 配置校验必须阻止缺失 `Type` 的 Hub,通过显式错误消息引导用户选择受支持值;内部设计需保留枚举扩展点,便于未来加入 apt/yum/composer/go proxy 等类型。
|
||||
- **FR-008**: 文档与示例配置需覆盖凭证字段的写法、敏感信息处理方式及最佳实践(例如不要提交到 Git),并说明 type 字段的当前支持列表及扩展策略。
|
||||
- **FR-009**: 测试覆盖需包括:配置解析(含非法组合)、凭证透传的集成测试、以及 Type 值驱动的分支逻辑。
|
||||
|
||||
### Key Entities *(include if feature involves data)*
|
||||
|
||||
- **HubConfig**: 描述单个代理 Hub 的所有属性,新增 `Username`、`Password`(可选字符串,按 Hub 粒度保存)、`Type`(枚举,默认 `generic-http`)。与 HubRegistry 绑定。
|
||||
- **AuthProfile**: 运行期派生实体,包含凭证存在性、认证模式、最后一次认证状态等,并与日志/metrics 关联。
|
||||
- **HubType**: 表示仓库协议类别(docker、npm、generic-http 等),驱动特定 Header、缓存策略或 future features。
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: 100% 的受保护仓库(需要 Basic/Bearer 凭证)可在下游匿名请求下成功响应,且无需再配置下游凭证。
|
||||
- **SC-002**: 代理日志中 `auth_mode=credentialed` 的请求,其 401/429 错误率较匿名模式下降 ≥80%(以相同上游的历史基线为对照)。
|
||||
- **SC-003**: 所有 Hub 配置在 `go test ./internal/config` 覆盖下均能校验通过,新增字段的解析、默认值和错误路径达到 100% 单元测试覆盖。
|
||||
- **SC-004**: 文档与 quickstart 示例更新完成后,内部演练中 3 名运维工程师可在 15 分钟内配置并验证 Docker、NPM 仓库的登录代理。
|
||||
155
specs/003-hub-auth-fields/tasks.md
Normal file
155
specs/003-hub-auth-fields/tasks.md
Normal file
@@ -0,0 +1,155 @@
|
||||
---
|
||||
|
||||
description: "Tasks for Hub 配置凭证字段"
|
||||
---
|
||||
|
||||
# Tasks: Hub 配置凭证字段
|
||||
|
||||
**Input**: Design documents from `/specs/003-hub-auth-fields/`
|
||||
**Prerequisites**: plan.md (required), spec.md (required), research.md, data-model.md, contracts/
|
||||
|
||||
**Tests**: 宪法 v1.0.0 要求覆盖配置解析、缓存读写、代理命中/回源与 Host Header 绑定,此清单在相关阶段加入对应测试任务。
|
||||
|
||||
**Organization**: Tasks are grouped by user story以支持独立实施与验证。
|
||||
|
||||
## Format: `[ID] [P?] [Story] Description`
|
||||
|
||||
- **[P]**: 可并行执行(触达不同文件/无直接依赖)
|
||||
- **[Story]**: 指明所属用户故事(Setup/Foundational/Polish 阶段不写)
|
||||
- 描述中必须包含精确文件路径
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Setup (Shared Infrastructure)
|
||||
|
||||
**Purpose**: 记录迁移策略、同步文档,让团队在单端口与凭证范围上达成一致。
|
||||
|
||||
- [X] T001 将全局 `ListenPort`/Hub 凭证迁移指南写入 `DEVELOPMENT.md` 与 `README.md`,提醒去除 `[[Hub]].Port`
|
||||
- [X] T002 补充 `CHANGELOG.md` 与 `specs/003-hub-auth-fields/quickstart.md` 的前置说明,列出新的配置字段及基本验证命令
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Foundational (Blocking Prerequisites)
|
||||
|
||||
**Purpose**: 改造配置与 server 启动流程,确保所有 Hub 共用单端口并具备新字段;完成前禁止进入任何用户故事。
|
||||
|
||||
- [X] T003 更新 `internal/config/types.go` / `internal/config/loader.go`,为 `GlobalConfig` 添加 `ListenPort`,为 `HubConfig` 添加 `Username`/`Password`/`Type`,并删除 Hub 级 `Port`
|
||||
- [X] T004 扩充 `internal/config/validation.go` 与 `internal/config/config_test.go`,覆盖 `ListenPort` 范围校验、Type 枚举校验及缺失 Type 报错
|
||||
- [X] T005 重构 `cmd/any-hub/main.go` 与 `internal/server/router.go`,仅根据全局 `ListenPort` 启动 Fiber,并在加载阶段检测到 Hub 级 `Port` 时报告迁移错误
|
||||
- [X] T006 [P] 更新 `internal/server/hub_registry.go` 及 `internal/server/hub_registry_test.go`,让 Host Registry 仅依赖 Host/Host:port 组合,去除对 per-Hub 端口的引用
|
||||
- [X] T007 [P] 调整 `configs/config.example.toml`、`configs/docker.sample.toml`、`configs/npm.sample.toml`,移除 Hub 端口字段并添加 `ListenPort`/`Type` 示例
|
||||
|
||||
**Checkpoint**: 单端口 + 新字段的配置/路由路径已可运行,各用户故事可并行推进。
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 1 - 配置上游凭证 (Priority: P1) 🎯 MVP
|
||||
|
||||
**Goal**: Hub 可配置上游凭证,CLI 回源时自动附带 Authorization,日志只输出掩码。
|
||||
|
||||
**Independent Test**: 使用带凭证的 `config.toml` 运行 `any-hub --check-config` 与 `go test ./tests/integration -run CredentialProxy`,无须下游凭证即可解除 rate-limit。
|
||||
|
||||
### Tests for User Story 1
|
||||
|
||||
- [X] T008 [P] [US1] 在 `tests/integration/credential_proxy_test.go` 构建带 Basic Auth 的 upstream stub,验证“无凭证失败→配置凭证成功”的流程
|
||||
|
||||
### Implementation for User Story 1
|
||||
|
||||
- [X] T009 [US1] 在 `internal/config/types.go` 与 `cmd/any-hub/main.go` 中保存可选凭证,并在所有 `logrus` 输出中仅显示掩码/存在性
|
||||
- [X] T010 [US1] 修改 `internal/proxy/handler.go`,依据 Hub 凭证自动附加 Authorization header,并在 401/429 时执行一次受控重试与错误字段记录
|
||||
- [X] T011 [US1] 更新 `README.md` 与 `quickstart.md`,新增凭证写法、敏感信息注意事项以及 `any-hub --check-config` 示例
|
||||
|
||||
**Checkpoint**: 代理可凭借配置凭证访问受限仓库,下游仍保持匿名体验。
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 2 - 下游透明体验 (Priority: P1)
|
||||
|
||||
**Goal**: 确保下游无需配置凭证即可访问,日志/观测字段体现 `auth_mode`、`hub_type` 与上游结果。
|
||||
|
||||
**Independent Test**: 运行 `tests/integration/credential_proxy_test.go` 的匿名客户端用例,并以 `npm --registry http://127.0.0.1:<ListenPort>` 手动验证日志输出。
|
||||
|
||||
### Tests for User Story 2
|
||||
|
||||
- [X] T012 [P] [US2] 扩展 `tests/integration/credential_proxy_test.go`,加入“不带 Authorization 仍命中凭证”与日志字段断言
|
||||
|
||||
### Implementation for User Story 2
|
||||
|
||||
- [X] T013 [US2] 在 `internal/logging/fields.go` 与 `internal/proxy/handler.go` 中输出 `hub_type`、`auth_mode`、`upstream_status`,并确保缓存命中/回源路径均记录
|
||||
- [X] T014 [US2] 在 `tests/integration/upstream_stub_test.go` 及 `quickstart.md` 中补充匿名客户端示例命令,指导如何验证透明代理
|
||||
|
||||
**Checkpoint**: 日志、quickstart 与匿名客户端流程可完整验证下游体验。
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: User Story 3 - 仓库类型适配 (Priority: P2)
|
||||
|
||||
**Goal**: 强制声明 Hub `Type`(docker/npm/go),日志与运行期可识别类型,为未来扩展留接口。
|
||||
|
||||
**Independent Test**: 使用覆盖三种 Type 的配置运行 `any-hub --check-config` 与 `go test ./internal/config`,非法/缺失 Type 会被拒绝,日志中能看到正确的 `hub_type`。
|
||||
|
||||
### Tests for User Story 3
|
||||
|
||||
- [X] T015 [P] [US3] 在 `internal/config/config_test.go` 新增表驱动测试,覆盖合法 Type、非法 Type、缺失 Type 的报错/提示
|
||||
|
||||
### Implementation for User Story 3
|
||||
|
||||
- [X] T016 [US3] 在 `internal/proxy/handler.go` 与 `internal/server/router.go` 加入 `switch Type`,目前仅设置日志/标签,并对未支持类型抛出明确错误
|
||||
- [X] T017 [US3] 更新 `quickstart.md` 及 `configs/*.sample.toml`,列出 Type 可选值与未来扩展策略
|
||||
|
||||
**Checkpoint**: Hub 类型被强制校验,日志和示例配置均反映正确值。
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Polish & Cross-Cutting Concerns
|
||||
|
||||
**Purpose**: 统一测试、文档及残留引用,确保产物满足宪法门槛。
|
||||
|
||||
- [X] T018 [P] 运行 `gofmt ./cmd ./internal ./tests` 与 `GOCACHE=/tmp/go-build go test ./...`,并把命令写入 `DEVELOPMENT.md`
|
||||
- [X] T019 清理 `DEVELOPMENT.md`、`README.md`、`specs/003-hub-auth-fields/plan.md` 中残留的 Hub 端口描述,确保只推荐全局 `ListenPort`
|
||||
- [X] T020 在 `CHANGELOG.md` 与 `quickstart.md` 中记录演练结果(docker + npm),并附一次手动验证日志
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & Execution Order
|
||||
|
||||
### Phase Dependencies
|
||||
|
||||
1. Setup → Foundational → 所有用户故事 → Polish
|
||||
2. Foundational 完成前,任何用户故事不得启动。
|
||||
3. US2 依赖 US1 产出的凭证注入,但可以在实现层并行。
|
||||
4. US3 仅依赖 Foundational,可与 US1/US2 并行实施。
|
||||
|
||||
### User Story Dependencies
|
||||
|
||||
- US1 完成后,即可单独交付 MVP。
|
||||
- US2 依赖 US1 的日志/凭证输出,但测试可提前编写。
|
||||
- US3 与其他故事仅在配置层相互作用,无硬依赖。
|
||||
|
||||
### Parallel Opportunities
|
||||
|
||||
- T006 与 T007 可由不同成员分别处理(registry vs. 示例配置)。
|
||||
- T008/T012/T015 测试任务都可在实现前准备并行执行。
|
||||
- 不同用户故事的实现(T009- T017)可由独立小组并行推进。
|
||||
- Polish 阶段 T018 与 T019/T020 可交由不同成员并行完成。
|
||||
|
||||
---
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### MVP First (User Story 1)
|
||||
1. 完成 Setup + Foundational,确认单端口与配置路径无误。
|
||||
2. 实施 US1(凭证字段 + 代理注入)并通过集成测试。
|
||||
3. 以此为最小可交付版本,供受限仓库使用。
|
||||
|
||||
### Incremental Delivery
|
||||
1. Increment 1: Setup + Foundational + US1 → 解锁凭证代理。
|
||||
2. Increment 2: US2 → 强化透明体验与观测性。
|
||||
3. Increment 3: US3 → 引入 Type 校验及扩展思路。
|
||||
4. Polish: 全量测试、文档与 quickstart 验证。
|
||||
|
||||
### Parallel Team Strategy
|
||||
- Team A:负责 Foundational + US1。
|
||||
- Team B:在 Foundational 完成后并行 US2(日志 + quickstart)。
|
||||
- Team C:并行 US3(Type 校验与示例)。
|
||||
- Polish 阶段由值班成员统一收尾。
|
||||
Reference in New Issue
Block a user