Skip to content

Draw what a shared map carries, and close two redaction gaps it found - #37

Merged
HarperZ9 merged 1 commit into
mainfrom
feat/art-record-card
Sep 3, 2026
Merged

Draw what a shared map carries, and close two redaction gaps it found#37
HarperZ9 merged 1 commit into
mainfrom
feat/art-record-card

Conversation

@HarperZ9

@HarperZ9 HarperZ9 commented Sep 3, 2026

Copy link
Copy Markdown
Owner

What this adds

A record card, docs/art/what-leaves.svg, embedded in the README under the privacy bullet. Seven rows: what git or the filesystem hands index on the left, what the written map ends up carrying in the middle, why it lands that way on the right. One row wears the hot mark, and it is portable turned off, the single setting that puts real absolute paths in the file.

The README already claimed a map is private by default. Nothing pictured it, and nothing let a reader see the shape of the claim without reading gitmeta.py and scan.py themselves.

Two redaction gaps, found by reading the code the card describes

Drawing a claim means checking it first. Two origins went through sanitize_credentials untouched:

origin before after
ssh://user:pw@host:22/o/r.git unchanged, password published ssh://<redacted>@host:22/o/r.git
https://h/r.git?access_token=v unchanged, token published ?access_token=<redacted>

The first because the userinfo rule was bound to https?://. The second because \b cannot match between _ and t, so a pattern anchored on a word boundary sees token and misses every prefixed spelling. Both sat under a module docstring calling the redaction always-on.

Publishing a diagram that advertised the gap seemed worse than fixing it, so the code is fixed. ssh://git@host still passes through whole: a username is not a secret, and blanking it costs a reader the half of the URL that says how the clone was set up.

This is a scope extension. The task was artwork. This changes security-relevant source, so review it as such.

What holds it

Ten new cases in tests/test_gitmeta.py: three password-carrying schemes, ten parameter names bare and prefixed, one ssh username that must stay, six ordinary remotes that must come back byte for byte. Reverting gitmeta.py to the merged version turns six of them red, so they are bound to the module rather than to a fixture.

The greedy value class after a credential name is kept on purpose. Stopping at & would uncover the following parameter, which may be a secret whose name this pattern does not know. More redaction is the safe direction, and the reasoning is now a comment in the code.

The card gate

tests/test_repo_art.py gains inline gates in this repository's plain-pytest shape, each with a docstring saying what it stops:

  • every key, value, note and the footnote measured against its column with the renderer's own width table
  • exactly one hot mark per card
  • no literal that rots in the value column
  • the README alt attribute is the one in the spec, because an <img> hides the description the SVG carries inside it
  • a control card that has to produce five complaints

The width check tests two failures, not one. A note that loses its ending to the wrapper is the obvious case. The quiet one is a single token longer than the column: greedy wrapping leaves it alone on its line, the joined text still equals the source, and the drawing runs off the page with every check green. A 120-character token draws 690px into a 376px column that way.

Measurement

Measured twice, against the renderer's width table and against the real Hanken Grotesk face the site serves:

widest right edge rule clears by
real face 905.8 916 10.2
renderer table 904.2 916 11.8

37 text elements, 19 of them grotesk. Nothing past the rule either way. The table is a class approximation (every lowercase letter one width), so the two numbers are expected to differ; a line full of wide letters is where it drifts.

Honest nulls

  • The renderer is now a twelfth copy of repo_art.py / repo_flow.py / repo_card.py across these repositories rather than a shared package. That is a real cost and it is not paid here.
  • repo_card.py has no treatment for an unverifiable verdict. The published site separates that tone by border and ring rather than hue; the card has neither. This card sidesteps the gap by marking the one row where something does leave.
  • NOTE_BUDGET equals the rule exactly, so the note column has zero designed margin. This card's widest note clears by 11.8 by table and 10.2 real, which is margin by wording rather than by geometry.
  • Repository-wide ruff (40) and mypy (29) findings exist on main and none of them touch the files changed here. CI runs pytest only.

🤖 Generated with Claude Code

The README says a map is private by default and then leaves a reader to
take that on trust. This adds the drawing that says it instead: seven
things git or the filesystem hands index, and what each one becomes in
the written file. One row is marked, and it is the setting that puts
real absolute paths in the map.

Writing it meant reading sanitize_credentials closely, and two origins
went through it untouched. A password in an ssh URL survived, because
the userinfo rule was bound to http and https. A parameter named
access_token survived, because a word boundary cannot match between an
underscore and a letter, so a pattern anchored on one sees token and
misses every prefixed spelling of it. Both sit under a module docstring
that calls the redaction always-on. Drawing the gap would have
advertised it, so the code is fixed and ten new cases hold it: three
password-carrying schemes, ten parameter names bare and prefixed, one
ssh username that stays because a username is not a secret, and six
ordinary remotes that must come back byte for byte. Reverting the module
turns six of them red.

The value class after a credential name still runs to the end of the
query. Stopping it at an ampersand would uncover the next parameter,
which may be a secret whose name this pattern does not know, so the
greedy read is the safe one and the reason is now in the code.

The card gate measures every row against its column with the renderer's
own width table, and it checks two failures rather than one. A note that
loses its ending is the obvious case. A single token longer than the
column is the quiet one: greedy wrapping leaves it alone on its line,
the joined text still equals the source, and the drawing runs off the
page with every check green. Both are proved failable by a control card.

Measured against the real Hanken Grotesk face as well as the renderer's
table: 37 text elements, widest right edge 905.8 real and 904.2 by
table, against a rule at 916.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@HarperZ9
HarperZ9 merged commit ae9cda0 into main Sep 3, 2026
2 checks passed
@HarperZ9
HarperZ9 deleted the feat/art-record-card branch September 3, 2026 16:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant