phase: 121_git_source_tokens
**Phase 121 final verification pass — all green** (all 4 tasks already in `complete/`; verified, no defects found, no changes needed) - Verified implementation vs phase design: migration `0021` (reversible, round-tripped via `alembic downgrade base` + `upgrade head` → head `0021`), `GitSource.token` column, `normalize_credential`/`clone_url_for`/`sanitize_url`, clone callers switched (`sync.py`, `import_docs.py`), masked token fields in add form + editor, `extra="forbid"` output shapes - Tests: `uv run pytest` → 2662 passed, 0 failed (exit 0); `uv run pytest --cov=app --cov-report=term-missing` → TOTAL **99%** (≥90% gate) - Lint/types: `uv run ruff check .` → All checks passed; `uv run pyright` → 0 errors, 0 warnings - E2E in isolation: `uv run pytest tests/e2e/test_git_source_tokens.py -v --no-cov` → **4 passed** Completion criteria: 1. Private repo (UI add or pasted embedded-token URL) clones with injected token; token absent from every API response, page text, title attr, and full HTML — **PASS** (integration raw-JSON assertions + E2E `_assert_token_nowhere`) 2. Legacy embedded-token rows still clone from stored URL; output sanitized — **PASS** (`test_sync_legacy_row_clones_with_original_stored_url`, `test_get_masks_legacy_embedded_token_row`, env-fallback masking) 3. Public/local sources byte-identical — **PASS** (verbatim-URL + no-userinfo-unchanged tests) 4. pytest / coverage / ruff / pyright — **PASS** (see above) 5. Commit + phase move — harness responsibility; task files already in `complete/`, changes left in working tree (no commit made, per protocol) Notable: no deviations; DB left at head, functional. Next pending phase: **122_image_documents** (then 123_chat_image_questions).
This commit is contained in:
@@ -286,6 +286,16 @@ class GitSource(Base):
|
||||
include_hidden: Mapped[bool] = mapped_column(
|
||||
Boolean, default=False, server_default=text("false"), nullable=False
|
||||
)
|
||||
#: Private-repo credential (phase 121, LOCKED A2): the PAT the owner
|
||||
#: types into the masked Sources-page field. NULL = public repo (or a
|
||||
#: legacy row whose credential is still embedded in ``url``). Stored
|
||||
#: plaintext BY NECESSITY — the repo must remain cloneable, so the
|
||||
#: raw credential must be recoverable at sync time; the DB is the
|
||||
#: trusted store and is never served to the UI. Injected into the
|
||||
#: clone URL ONLY at clone time
|
||||
#: (:func:`app.rag.git_sources.clone_url_for`); NEVER returned by
|
||||
#: any API shape (the output models gain no token field).
|
||||
token: Mapped[str | None] = mapped_column(Text, default=None)
|
||||
added_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user