pr-publication-safety

SkillMedia

Use when changing PR body rendering, home-path redaction, artifact path publication, or pipeline-attestation markers.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the pr-publication-safety skill

What this skill tells your AI

The instructions your AI receives, as published by kunchenguid/no-mistakes in .agents/skills/pr-publication-safety/SKILL.md and read by ahel’s review.

Home-Path Redaction in Published PR Content (security)

  • internal/safepath is the one owner of home-directory redaction, the path analogue of internal/safeurl. RedactText rewrites the process's own home plus /home/<user>, /Users/<user>, and C:\Users\<user> to ~, unconditionally and for every occurrence. Add new shapes there rather than scrubbing paths at a call site. Candidate resolution must stay free of filepath.IsAbs/VolumeName and of any reliance on filepath.Clean's separator normalisation: those answer for the build platform, and on Windows IsAbs discards the POSIX-rooted HOME that Git Bash, MSYS2, and Cygwin set - silently disabling redaction instead of failing. Regression: TestUsableHomeCandidate_AcceptsBothPlatformSpellings, TestHomeCandidates_AreSeparatorSpellingIndependent.
  • PRStep.buildPRContent is the single render boundary: it drafts through draftPRContent and returns redactPRContent(content), and Execute publishes exactly that. Every source that can reach a PR body - agent prose, extracted intent, findings, fix summaries, step errors, artifact path, artifact captions, and captured output embedded from evidence files - is covered there, so a new rendering path cannot reintroduce the leak. Redaction runs after every length cap, which is only safe because the placeholder is never longer than the path it replaces.
  • The artifacts[].path description in testFindingsSchema (common.go) must not solicit absolute paths, and must not forbid them either. The renderer's allowlist is the worktree or the run's evidence directory and a path under neither is dropped, while the evidence directory defaults under the operator's home - so soliciting more just re-supplies what the boundary has to strip, and a blanket "never report a home directory path" clause makes an obedient agent drop its own evidence. Publication safety is the pr.go boundary's job; the schema only stops soliciting paths from elsewhere on the machine. Regressions: TestTestFindingsSchema_DoesNotSolicitAbsolutePaths, TestTestFindingsSchema_KeepsEvidenceDirectoryPathsReportable.
  • Two other public surfaces deliberately do NOT share this rendering and are not covered: agent-authored commit subjects (commitAgentFixes -> Commit.RenderFixMessage), which reach the remote through Push, and the opt-in evidence branch (test.evidence.store_in_repo), which copies artifact files verbatim. Keep the internal/safepath package doc honest about that scope.
  • The PR body must contain exactly ONE live pipeline-attestation marker, the run's own. require-no-mistakes (.github/actions/require-no-mistakes/verify.py) binds the FIRST marker in the RAW body to the PR head, so a foreign copy placed earlier fails a PR the pipeline did produce - and a code fence is no defense, because that scan is raw text. Step agents embed foreign markers routinely, by capturing a generated PR body as evidence.
  • A CI repair that publishes a new head rewrites only that live marker's head_sha in the current PR body (restampPublishedAttestation) and does not send a title. It never inserts a marker that was not already there. Hosts without a PR content reader skip the restamp instead of failing the push. Regressions: TestCIStep_PublishRepairRebindsAttestationAcrossRepairPushes, TestCIStep_PublishRepairDoesNotMintAttestation, TestCIStep_PublishRepairSkipsRestampWithoutReader, TestRestampPRAttestation_PreservesContentEditedWhilePreparingRewrite, TestUpdatePROmitsTitleWhenEmpty.
  • Neutralize at the assembly choke point (appendGeneratedSectionsToCleanBodyWithinLimit plus the two intent paths), never per render path. pipelineMD alone carries the real marker and is left intact; BuildPipelineSummaryFor neutralizes its own step-detail blocks, which quote agent text. A first attempt put this in escapePipelineFoldMarkers - per-render-path - and shipped three live foreign markers to #831 anyway. Regressions: TestPRStep_ForeignAttestationsInEveryComponentDoNotShadowTheRealOne (all components at once), plus the per-component guards in pr_test.go.
  • Regressions: internal/safepath/redact_test.go, internal/pipeline/steps/pr_homepath_test.go.

Signals

GitHub stars
8k
Forks
855
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
pr-publication-safety
Source
github.com/kunchenguid/no-mistakes