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:
+37
-5
@@ -625,10 +625,11 @@
|
||||
to the database.
|
||||
</p>
|
||||
|
||||
<!-- Add form: visible label + mono URL input + brand button
|
||||
(dark ink on brand 5.2:1). §7.4 never-stale: the button
|
||||
disables + relabels "Adding…" while the POST is in flight
|
||||
and re-enables on success AND failure (the input is kept
|
||||
<!-- Add form: visible label + mono URL input + the optional
|
||||
masked token field (phase 121) + brand button (dark ink
|
||||
on brand 5.2:1). §7.4 never-stale: the button disables +
|
||||
relabels "Adding…" while the POST is in flight and
|
||||
re-enables on success AND failure (the inputs are kept
|
||||
on failure, same as the tuning forms). -->
|
||||
<form id="git-source-form">
|
||||
<label for="git-source-url">Add a git source</label>
|
||||
@@ -641,6 +642,22 @@
|
||||
placeholder="https://github.com/you/your-repo.git"
|
||||
required
|
||||
>
|
||||
<!-- Phase 121 (task 03, LOCKED A2): the optional masked
|
||||
private-repo credential — type=password +
|
||||
autocomplete=off (a PAT is not a site credential: no
|
||||
browser save offer). Blank = the POST omits the key
|
||||
(None = no credential); the token is write-only — it
|
||||
never round-trips (the API shapes carry no token
|
||||
field). -->
|
||||
<label for="git-source-token">Token <span class="field-hint">optional — private repos</span></label>
|
||||
<input
|
||||
id="git-source-token"
|
||||
name="token"
|
||||
type="password"
|
||||
maxlength="500"
|
||||
autocomplete="off"
|
||||
placeholder="ghp_… or another PAT"
|
||||
>
|
||||
<button type="submit" id="git-source-add">Add source</button>
|
||||
<p class="git-source-error" id="git-source-error" role="alert" hidden></p>
|
||||
</form>
|
||||
@@ -784,12 +801,16 @@
|
||||
while the PATCH is out). Stored rows only (A3) — the
|
||||
per-row button lives in git-sources.js's makeRow; this
|
||||
is the page-local dialog it opens. -->
|
||||
<!-- Phase 121 (task 03): the per-row editor gains the
|
||||
optional masked token field (LOCKED A2) — the title
|
||||
widens from "Ignored files and folders" to the dialog's
|
||||
actual scope (the row's settings). -->
|
||||
<div class="ignore-editor" id="ignore-editor-dialog" role="alertdialog"
|
||||
aria-modal="true" aria-labelledby="ignore-editor-title"
|
||||
aria-describedby="ignore-editor-copy" hidden>
|
||||
<div class="ignore-editor-backdrop" aria-hidden="true"></div>
|
||||
<div class="ignore-editor-panel">
|
||||
<h2 class="ignore-editor-title" id="ignore-editor-title">Ignored files and folders</h2>
|
||||
<h2 class="ignore-editor-title" id="ignore-editor-title">Source settings</h2>
|
||||
<code class="ignore-editor-source" id="ignore-editor-source"></code>
|
||||
<p class="ignore-editor-copy" id="ignore-editor-copy">
|
||||
One path per line. A file is ignored when its path in the
|
||||
@@ -801,6 +822,17 @@
|
||||
<textarea class="ignore-editor-textarea" id="ignore-editor-textarea"
|
||||
rows="6" spellcheck="false"
|
||||
placeholder="my/files/"></textarea>
|
||||
<!-- Phase 121 (task 03, LOCKED A2): the masked
|
||||
private-repo credential — type=password +
|
||||
autocomplete=off (a PAT is not a site credential).
|
||||
BLANK = the PATCH omits the key (the tri-state: no
|
||||
change — the row's stored token is kept). The field
|
||||
is NEVER prefilled (the API has no token field to
|
||||
read it from). -->
|
||||
<label class="ignore-editor-label ignore-editor-token-label" for="ignore-editor-token">Token <span class="field-hint">optional — private repos</span></label>
|
||||
<input class="ignore-editor-token" id="ignore-editor-token"
|
||||
type="password" maxlength="500" autocomplete="off"
|
||||
placeholder="leave blank to keep the current token">
|
||||
<p class="ignore-editor-error" id="ignore-editor-error" role="alert" hidden></p>
|
||||
<div class="ignore-editor-actions">
|
||||
<button type="button" class="ignore-editor-btn ignore-editor-cancel"
|
||||
|
||||
Reference in New Issue
Block a user