mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-09-17 08:36:25 +00:00
The quick start walked a new user into gh repo fork - forks of public repos are always public - and two steps later had /setup write personal data into tracked files, with the only complete warning in SETUP.md section 8, a section about pulling updates that a first-time user has no reason to open during onboarding. A real user hit exactly this (#345). The warning now sits adjacent to both fork commands (README step 1, SETUP.md section 2, both pointing at section 8's private-remote recipe), and /setup checks the origin's visibility BEFORE writing anything: a public-fork origin gets a confirm-first warning instead of a note after every file is on disk. A private origin, no origin, or a non-git directory continues silently. Reported by @basilevs with a complete reproduction and fix analysis; this implements his fixes (1) and (4). Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ab5d23bad4
commit
34b8b3f91f
@@ -0,0 +1,85 @@
|
||||
"""Guards for the onboarding privacy warnings (issue #345).
|
||||
|
||||
The README's quick start walks a new user into creating a public fork
|
||||
(forks of public repos cannot be private) and then has /setup write
|
||||
personal data into tracked files, with the only complete warning sitting
|
||||
in SETUP.md section 8 - a section about pulling updates, downstream of
|
||||
the decision it should inform. A real user hit exactly this. These tests
|
||||
pin that the warning lives at the point of decision (adjacent to both
|
||||
fork commands) and that /setup checks the origin's visibility BEFORE
|
||||
writing anything, not in its closing notes.
|
||||
"""
|
||||
import re
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
README = REPO / "README.md"
|
||||
SETUP_GUIDE = REPO / "SETUP.md"
|
||||
SETUP_COMMAND = REPO / ".claude" / "commands" / "setup.md"
|
||||
|
||||
|
||||
def section(text: str, heading: str) -> str:
|
||||
"""Body of a markdown section up to the next heading of the same level."""
|
||||
level = heading.split(" ")[0]
|
||||
pattern = re.compile(
|
||||
rf"^{re.escape(heading)}\n(.*?)(?=^{level} |\Z)", re.MULTILINE | re.DOTALL
|
||||
)
|
||||
match = pattern.search(text)
|
||||
return match.group(1) if match else ""
|
||||
|
||||
|
||||
class TestForkWarningsAtTheDecisionPoint(unittest.TestCase):
|
||||
def assert_warns(self, body: str, where: str):
|
||||
self.assertRegex(
|
||||
body,
|
||||
re.compile(r"public", re.IGNORECASE),
|
||||
f"{where}'s fork section must say the fork will be public",
|
||||
)
|
||||
self.assertIn(
|
||||
"personal data",
|
||||
body,
|
||||
f"{where}'s fork section must say /setup writes personal data into tracked files",
|
||||
)
|
||||
self.assertRegex(
|
||||
body,
|
||||
re.compile(r"section 8|§8|#8-pulling", re.IGNORECASE),
|
||||
f"{where}'s fork section must point at SETUP.md section 8's private-remote recipe",
|
||||
)
|
||||
|
||||
def test_readme_quick_start_warns_next_to_the_fork_command(self):
|
||||
body = section(README.read_text(encoding="utf-8"), "### 1. Fork and clone")
|
||||
self.assertIn("gh repo fork", body, "sanity: the fork command lives in this section")
|
||||
self.assert_warns(body, "README")
|
||||
|
||||
def test_setup_guide_warns_next_to_the_fork_command(self):
|
||||
body = section(SETUP_GUIDE.read_text(encoding="utf-8"), "## 2. Fork and clone")
|
||||
self.assertIn("gh repo fork", body, "sanity: the fork command lives in this section")
|
||||
self.assert_warns(body, "SETUP.md")
|
||||
|
||||
|
||||
class TestSetupChecksOriginBeforeWriting(unittest.TestCase):
|
||||
def test_preflight_exists_and_precedes_profile_generation(self):
|
||||
text = SETUP_COMMAND.read_text(encoding="utf-8")
|
||||
self.assertIn(
|
||||
"git remote get-url origin",
|
||||
text,
|
||||
"/setup must check where the working copy would publish to",
|
||||
)
|
||||
preflight_at = text.index("git remote get-url origin")
|
||||
writes_at = text.index("## Step 3: Generate Profile Files")
|
||||
self.assertLess(
|
||||
preflight_at,
|
||||
writes_at,
|
||||
"the origin check must run before any profile file is written - the "
|
||||
"existing Step 4 note fires after everything is already on disk",
|
||||
)
|
||||
self.assertIn(
|
||||
"public",
|
||||
text[max(0, preflight_at - 2000) : preflight_at + 2000].lower(),
|
||||
"the preflight must be about public visibility, not just remote presence",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user