技能创建器
skill-creator
创建、改进和评估自定义技能,把专业流程转化为可重复使用的 AI 能力。
redact-for-public-disclosure【数据与研究】Redact reverse-engineering findings for public disclosure while keeping methodology, generalizable patterns, teaching value. Cover private-vs- public repo split, deny-list pattern care, orphan-commit publish pattern that prevents `git log` leaks, category-based redaction calibration (methodology/pattern/version-finding/internal), `check-redaction.sh`…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
git log leaks, category-based redaction calibration
(methodology/pattern/version-finding/internal), check-redaction.sh-
style CI gate that blocks merges when deny-listed pattern appears. Use
when publishing findings about CLI harness you don't own, when prepare
upstream proposals to unrelated project, when archive private research
repo for public reference.
license: MIT
allowed-tools: Read Write Edit Bash Grep
metadata:
author: Philipp Thoss
version: "1.0"
domain: investigation
complexity: intermediate
language: multi
tags: redaction, disclosure, deny-list, orphan-commit, ci-gate, research-publishingSplit reverse-engineering research repo into private source-of-truth and public-disclosure subset using redaction checker, pattern deny-lists, orphan-commit publish pattern. Methodology travels; specific findings stay private.
public/ worktree) where redacted content publishesBefore write or promote any content, sort each fact into one of four categories. Category determines whether and when it ships.
| Category | Definition | Shareable? |
|---|---|---|
| methodology | The how of investigation, independent of any specific finding | Always |
| generic pattern | Class-level observations (e.g., "harnesses commonly use a single-prefix flag namespace") | Yes |
| version-specific finding | Concrete observation tied to a specific release (e.g., "in vN.M, the gate defaults off") | Only after the version-lag cool-off |
| live internal | Minified names, byte offsets, dark flag names, current-version gate logic, PRNG/salt constants, internal codenames | Never |
Tag each draft section, capture log, or note with category before review for publication. Section that mixes categories splits — methodology lifts out clean. Rest stays private.
Got: Every candidate fact has category label. Drafts intended for public mirror contain only methodology and generic-pattern entries (plus version-specific findings older than cool-off).
If fail: Fact resists categorization? Treat as live internal by default. Re-categorize only after explicit review against version-lag policy.
Decide up front how many versions sit between "current" and "shareable." Two is typical: current + 1 prior stay private; older patterns may be discussed. Write policy into private repo (e.g., REDACTION_POLICY.md) so future-you no need re-derive it.
# Redaction Policy
Version-lag cool-off: **2 releases**.
- Current release (vN): all version-specific findings PRIVATE.
- Previous release (vN-1): all version-specific findings PRIVATE.
- Releases vN-2 and earlier: version-specific findings may move to public draft after Step 5 review.
Source of truth for "current": output of `monitor-binary-version-baselines`.
Owner: <name>. Reviewed quarterly.
"Current" version must be empirical (read from installed binary), not administrative. Tie policy to baseline scanner output, not calendar.
Got: Committed REDACTION_POLICY.md in private repo with explicit cool-off and owner.
If fail: Stakeholders cannot agree on cool-off? Default to most conservative proposal. Cool-offs can shorten later; recall a leak cannot.
Maintain patterns in single executable script that is source of truth for redaction policy. Script lives in private repo (tools/check-redaction.sh). Runs against public mirror.
#!/usr/bin/env bash
set -u
PUBLIC_REPO="${1:-./public}"
LEAKS=0
PATTERNS=(
"minified identifier shape|<regex matching short bundle-style identifiers>"
"vendor-prefixed flag|<regex matching the vendor's flag prefix>"
"PRNG/salt constant|<regex matching the specific constants>"
)
for entry in "${PATTERNS[@]}"; do
desc="${entry%%|*}"
pattern="${entry##*|}"
if rg -q "$pattern" "$PUBLIC_REPO"; then
echo "LEAK: $desc"; LEAKS=$((LEAKS+1))
fi
done
exit $LEAKS
Each entry has human-readable label and regex. One entry per sensitive identifier shape (not per literal string — shapes survive version churn). Exit code = number of leaks; clean run exits 0.
Got: tools/check-redaction.sh ./public-mirror runs in under a second on small repo. Exits 0 when nothing matches.
If fail: rg unavailable? Fall back to grep -rqE. Patterns too broad (every run reports leaks)? Narrow at source, no add suppressions.
When Phase 1-4 finding could leak through draft, extend scanner before draft is written. Drafts cheap; teaching scanner new patterns durable.
Workflow:
tools/check-redaction.sh (label + regex).This inverts usual order: scanner updates first, draft second. Scanner becomes executable specification of "what is too sensitive to publish." Draft cannot accidentally outpace it.
Got: Pattern entries in tools/check-redaction.sh predate any public-mirror content that could match them. git log tools/check-redaction.sh shows scanner updates landing before related draft commits.
If fail: Scanner updates lag drafts? Audit public mirror against new pattern immediately. Redact, then commit scanner update with note explaining discovered pattern.
Define explicit allow-list of files that sync to public mirror. New files default private; promotion requires redaction-check clearance.
# tools/public-allowlist.txt
README.md
LICENSE
guides/methodology-overview.md
guides/category-classification.md
docs/contributing.md
tools/sync-to-public.sh reads allow-list, copies only those files to public mirror, exits non-zero if allow-list references file that does not exist (catches typos).
#!/usr/bin/env bash
set -eu
PRIVATE_ROOT="${1:?private repo path required}"
PUBLIC_ROOT="${2:?public mirror path required}"
ALLOWLIST="$PRIVATE_ROOT/tools/public-allowlist.txt"
while IFS= read -r path; do
[ -z "$path" ] && continue
case "$path" in \#*) continue ;; esac
src="$PRIVATE_ROOT/$path"
dst="$PUBLIC_ROOT/$path"
if [ ! -e "$src" ]; then
echo "MISSING: $path"; exit 2
fi
mkdir -p "$(dirname "$dst")"
cp -a "$src" "$dst"
done < "$ALLOWLIST"
Promotion needs three things in order: file added to allow-list, file passes redaction check, reviewer confirms category labels from Step 1.
Got: Public mirror contains exactly files listed in tools/public-allowlist.txt. No file appears in public mirror that is not on allow-list.
If fail: File appears in public mirror but missing from allow-list? Treat as leak event — investigate how it arrived, then either remove or formally promote it after redaction review.
Public mirror is single git commit --orphan-rooted commit recreated at each publish. This prevents git log on public repo from exposing pre-redaction drafts.
# In the public mirror (separate repo or worktree)
cd /path/to/public-mirror
git checkout --orphan publish-tmp
git rm -rf . # Clear the index
# Sync from private using the allow-list
bash /path/to/private/tools/sync-to-public.sh /path/to/private .
git add -A
git commit -m "Publish: <date>"
git branch -D main 2>/dev/null || true
git branch -m main
git push --force origin main
Public repo git log shows exactly one commit. Prior drafts and any redaction iterations stay in private repo history. No git log -p, git reflog, or branch listing on public repo can recover pre-redaction content because never committed there.
Got: git log --oneline on public mirror shows single commit per publish. No references to private repo history (no parent SHAs, no merge commits, no tags from private repo) appear.
If fail: git push --force rejected (branch protection)? Open single-commit pull request from clean orphan branch instead. Never solve rejection by pushing private history.
Run tools/check-redaction.sh on every commit to public-sync branch. Failed check blocks publish, not just warns.
# .github/workflows/redaction-check.yml (in the public mirror repo)
name: redaction-check
on:
push:
branches: [main, publish-*]
pull_request:
branches: [main]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install ripgrep
run: sudo apt-get update && sudo apt-get install -y ripgrep
- name: Fetch redaction scanner
env:
GH_TOKEN: ${{ secrets.PRIVATE_REPO_TOKEN }}
run: |
gh api repos/<org>/<private-repo>/contents/tools/check-redaction.sh \
--jq .content | base64 -d > check-redaction.sh
chmod +x check-redaction.sh
- name: Run scanner
run: ./check-redaction.sh .
Two design choices:
Got: Pushes that introduce deny-listed pattern fail CI; publish does not land. Maintainers see failing label (e.g., LEAK: vendor-prefixed flag) without seeing regex itself.
If fail: Private-repo token cannot be granted to public CI? Embed only minimum-leak portion of scanner in public repo (broad shape patterns that no themselves identify vendor) and run full scanner pre-push from private repo.
When scanner trips on legitimate content, prefer narrow pattern over add ignore-line. Broad deny-lists with local suppressions rot fast — six months later no one remembers why a particular line was suppressed, and next leak slides past unnoticed.
Decision tree:
check-redaction.sh linking to case that motivated it.# REASON: comment that states why suppression safe. Date the comment.# Bad — mystery suppression
echo "API endpoint pattern" >> ignore.txt
# Good — narrowed pattern with rationale
# Pattern v2: tightened from `\bgate\(` to `\bgate\(['\"][a-z]+_phase` after
# legitimate `gate(true)` calls in our own SDK examples started matching. 2026-04-15.
PATTERNS+=("vendor flag predicate|\\bgate\\(['\"][a-z]+_phase")
Got: Each scanner pattern has zero or one inline comment explaining tightening. Suppressions, if any, carry date and rationale.
If fail: Suppressions accumulate (more than one per quarter)? Deny-list is mis-shaped. Schedule redaction-policy review. Rebuild patterns from categorized fact inventory.
Not all redaction work is incident-driven. Run periodic sweep (monthly typical) that re-categorizes most recent additions to private repo and re-runs scanner against public mirror. Drift catches itself before it becomes incident-grade.
Sweep checklist:
tools/check-redaction.sh against public mirror (should still exit 0)tools/public-allowlist.txt matches actual public-mirror file setGot: Short sweep log per month in private repo (e.g., sweeps/2026-04.md) with checklist outcomes and any actions taken.
If fail: Sweep repeatedly skipped? Automate calendar reminder. Sweep keeps finding same drift? Workflow upstream is the problem — investigate why categorization gets skipped at draft time.
tools/public-allowlist.txttools/check-redaction.sh ./public-mirror exits 0git log --oneline on public mirror shows single orphan commit per publishREDACTION_POLICY.md exists in private repo with explicit version-lag cool-offacme_widget_v3, widget_handler_42) — clearly invented, never traceable to real product.git rebase or git filter-branch to scrub leak in place on public repo. Force-pushing rewritten history still leaves traces in clones and forks. Orphan-commit publish pattern = structural fix; ad-hoc history rewriting = not.LEAK: vendor-prefixed flag) should appear in public CI logs.monitor-binary-version-baselines — Phase 1, baselines feed version-lag policy: what counts as "current" is empirical fact, not calendar factprobe-feature-flag-state — Phases 2-3, classification findings here enter redaction pipeline at category step (Step 1)conduct-empirical-wire-capture — Phase 4, capture artifacts (wire logs, payload schemas) need redaction before any can be referenced publicsecurity-audit-codebase — both pipelines benefit from deny-list-style scanning; this skill specializes for research disclosure rather than secret leakagemanage-git-branches — orphan-commit publish pattern is branch operation; safe execution requires branch hygiene practices documented there