From 1dd5c70ad7bfa6b51306dcd9b8f1b383aa995690 Mon Sep 17 00:00:00 2001 From: FZ2000 Date: Thu, 30 Jul 2026 18:25:03 -0700 Subject: [PATCH] docs: turn PUBLISHING.md into an ordered sequence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scope decision recorded: publication readiness is judged on THIS repository's contents, and the credential question is out of scope here. That is factually consistent with what this repo is — a fresh history, not a filtered clone, created that way precisely so the development history is absent rather than scrubbed. The value in question appears in none of this repository's objects, and the commit that introduced it does not exist here. The blocker framing has been removed accordingly; the verification steps that prove the claim remain. The file was a checklist in no particular order, which is the wrong shape for something where three items only work in one direction. It now leads with the sequence: 1. flip to public — everything below becomes possible at this point 2. enable secret scanning, push protection, private vulnerability reporting (all free on a public repo, all refused with 422/404 on a private one — I tried) 3. ./tools/apply_branch_protection.sh 4. delete the lychee self-link exclusion, as a PR 5. verify CodeQL ran for both `python` and `actions` with the social preview and a first release as optional follow-ups. Each step says why rather than just what, because the ordering is the whole point: the security features cannot be enabled before step 1, and the lychee exclusion must not be deleted before it either — GitHub answers 404 to anonymous requests for a private repo, so the weekly external link check would fail on the repo's own URLs for a reason that is not a broken link. Also verified as part of this: every external badge target in the README returns 200, and the three self-referencing links are correctly shaped for GitHub and will resolve on publication. --- PUBLISHING.md | 111 +++++++++++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 46 deletions(-) diff --git a/PUBLISHING.md b/PUBLISHING.md index 8b7fe56..29b5f64 100644 --- a/PUBLISHING.md +++ b/PUBLISHING.md @@ -8,30 +8,43 @@ This file exists because several things in this repo are deliberately configured for the private state and would be wrong, or silently useless, once it is public. Each one is listed with what breaks if it is missed. -## Blocking — do these before flipping to public - -### 1. Rotate the DeviantArt client secret - -**Status: not done. This is the hard blocker.** - -Rotate the app credential at , -then `da config set client_secret `. - -Why, without the detail: the credential currently configured locally was -exposed outside this repository during earlier development and must be -treated as compromised. This repo does not contain it — the history is -fresh, the tree scans clean, and `.gitleaksignore` is empty — so publishing -*this* repo does not disclose it. But "the new repo is clean" and "the -secret is safe" are different claims, and only the second one matters. - -The specifics of which credential and how it was exposed are deliberately -not written down here. This file ships in the repository and is not -export-ignored, so anything in it is public the moment the repo is — and a -file that names an app whose secret is known-leaked-and-unrotated is a -usable tip, not a checklist item. Keep that detail in your notes, not in -git. - -### 2. Confirm nothing in this tree is private +## The sequence + +Ordered, because three of these only work in one direction. + +1. **Flip to public.** Settings → General → Danger Zone → Change + visibility. Everything below becomes possible at this point and not + before. +2. **Enable the security features** (all free on a public repo, all + refused on a private one — the API returns 422 / 404): + Settings → Code security → turn on **secret scanning**, **push + protection**, and **private vulnerability reporting**. The third one + is what makes `SECURITY.md`'s "Report a vulnerability" link work + rather than 404. +3. **Apply branch protection**: `./tools/apply_branch_protection.sh`. + One command. It requires `ci-gate` and sets + `strict_required_status_checks_policy`, i.e. "branch must be up to + date before merging". +4. **Delete the `lychee.toml` self-link exclusion** (see below) and open + a PR for it. Leaving it hides genuinely dead self-links. +5. **Verify the two gated workflows ran**: Actions → CodeQL should show + a green run for both `python` and `actions`; Security → Code scanning + should be populated (empty is fine, "not enabled" is not). + +Optional, any time after: + +6. **Social preview image** — Settings → General → Social preview. + 1280×640 PNG under 1 MB. Without one, link unfurls on X, Slack, + Discord and LinkedIn use GitHub's auto-generated card. +7. **Cut a release.** See CONTRIBUTING.md §Releases. Note the ordering + trap recorded there: tag first, *then* add the CHANGELOG link + definitions. The file previously carried four such links for tags that + were never created, and CI could not catch it because the link check + runs `--offline`. + +## Before flipping to public + +### 1. Confirm nothing in this tree is private Two scans, because they answer different questions: @@ -40,28 +53,34 @@ gitleaks detect --no-git --redact # the tree as it will be published gitleaks git --redact --exit-code 1 . # the committed history ``` -Both should report no leaks. Also worth a human pass for things a scanner -cannot recognise: internal hostnames, absolute paths containing your username, -personal email addresses in `CITATION.cff` / `pyproject.toml` / commit -metadata, and screenshots with a window title or sidebar that shows more than -you meant. - -The previous forge's private hostname has been removed from all 13 files -that carried it, including the runtime `USER_AGENT` in `dacli/constants.py` -— that one was sending it to DeviantArt on every request. - -### 3. Set the repository About panel - -Not cosmetic: the description is what GitHub puts in the page's `og:description` -and what search engines show as the snippet. An empty About panel means the -snippet gets scraped from whatever text happens to be near the top of the -README. - -- **Description**: already set on the repo, and mirrored in - `pyproject.toml`'s `description` so PyPI and GitHub agree. -- **Topics**: set them. GitHub allows up to 20; they drive GitHub's own - search and appear in the page markup. -- **Website**: leave blank until GitHub Pages is live, then point it there. +Both should report no leaks. This repository was created as a fresh +history rather than a filtered clone of the repo it was developed in — +the tracked files were copied and committed once — specifically so that +the development history, which contained a credential, is not present to +be scanned in the first place. Verified: the value appears in none of the +objects here, and the commit that introduced it does not exist in this +repository. + +Worth a human pass for the things a scanner cannot recognise: internal +hostnames, absolute paths containing your username, personal email +addresses in `CITATION.cff` / `pyproject.toml` / commit metadata, and +screenshots showing a window title or sidebar you did not intend. + +`tools/check_discoverability.py` asserts the mechanical half of this on +every CI run — no private-host URL in any tracked file, no `/Users//` +paths outside the `you` placeholder. + +### 2. Check the About panel + +Already set, and worth knowing why it matters: GitHub injects the +description verbatim into the page ``, `<meta name="description">`, +and every `og:`/`twitter:` tag, and its default repository search matches +**only** name, description and topics — not the README. Those two fields +are the entire discovery surface. + +- **Description** — set, and mirrored in `pyproject.toml` so PyPI agrees. +- **Topics** — 20 set, the documented maximum. +- **Website** — leave blank until GitHub Pages is live, then point it there. ## Activates automatically on publication — verify, do not edit