Skip to content

fix(scorecard): emit basename for target.path to stop home-dir PII leak - #39

Merged
brettdavies merged 1 commit into
devfrom
fix/target-path-basename
Apr 30, 2026
Merged

fix(scorecard): emit basename for target.path to stop home-dir PII leak#39
brettdavies merged 1 commit into
devfrom
fix/target-path-basename

Conversation

@brettdavies

@brettdavies brettdavies commented Apr 30, 2026

Copy link
Copy Markdown
Owner

Summary

target.path in the JSON scorecard previously emitted the canonicalized absolute path from Project::discover
(e.g. /home/<user>/dev/agentnative-cli). That value flows into committed scorecards under
agentnative-site/scorecards/, README badge URLs, Show HN comment paste-throughs, and any artifact an agent posts to
a PR or issue. Three PII vectors leaked through it:

  • operator username via /home/<user>/, /Users/<user>/, C:\Users\<user>\
  • org/employer directory structure (e.g. /home/<user>/work/<company>/...)
  • personal directory layout intent (~/dev vs ~/code vs ~/projects)

This PR switches target.path to the basename of the resolved target: the directory name in project mode, the
file name in binary mode. That carries identical identifying signal to tool.name (the slug used by /score/<slug>
URLs and badge embeds); anything richer was information leakage with no compensating consumer use. command mode is
unchanged (always null).

No schema_version bump: target.path stays string | null, always-present-null contract holds, no key changes.
The schema_version field exists to signal shape changes for consumer feature-detection; this is a value-content
fix on an existing key.

Changelog

Fixed

  • target.path in anc check --output json now emits the basename of the resolved target instead of the
    canonicalized absolute path, eliminating a home-directory / username PII leak that flowed into committed scorecards,
    badge URLs, and agent-posted artifacts. Project mode emits the directory name (e.g. "agentnative-cli"); binary
    mode emits the file name (e.g. "anc"); command mode unchanged at null. No schema bump: value semantics
    changed, schema shape did not.

Type of Change

  • fix: Bug fix (non-breaking change which fixes an issue)

Related Issues/Stories

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • All tests passing

Test Summary:

  • Unit tests: 535 passing (no count change; the basename helper is an internal refactor, integration tests carry the new assertions).
  • Integration tests: tests/scorecard_schema_v05.rs: project-mode test now pins parsed["target"]["path"] == "perfect-rust" (was: just is_string()); binary-mode test pins "test.sh"; new test schema_v05_target_path_carries_no_separators rejects any forward or back slash in the value (regression guard against richer path representations creeping back in). 51 tests in this suite (was 50).
  • Manual / dogfood: cargo build --release green; anc check . --output json | jq .target.path returns "agentnative-cli" (was: /home/brett/dev/agentnative-cli); binary mode returns "anc" (was: full path); command mode returns null (unchanged).

Files Modified

Modified:

  • src/main.rs: build_target_info now uses new basename_string() helper. Doc-comment expanded with PII-leak rationale.
  • src/scorecard/mod.rs: TargetInfo doc-comment specifies basename semantics + leak rationale.
  • tests/scorecard_schema_v05.rs: tightened project + binary mode assertions to pin literal basename values; added schema_v05_target_path_carries_no_separators regression guard.
  • CLAUDE.md: scorecard 0.4 target bullet updated with leak rationale + pointer to the regression-guard test.

Created:

  • None.

Renamed:

  • None.

Deleted:

  • None.

Breaking Changes

  • No breaking changes

The schema's contract (key presence, type) is unchanged; only the value-content shape changes. Any consumer relying
on absolute-path semantics was already fragile across hosts (CI's /runner/work/... vs dev's /home/<user>/...);
tool.name is the right field for cross-host correlation and is unaffected.

Deployment Notes

  • No special deployment steps required

Existing scorecards committed under agentnative-site/scorecards/ retain their old absolute-path values until
re-scored; the next anc check run on each tool emits the basename. Site renderers that read target.path for
display will show shorter strings going forward, with no consumer feature-detection needed.

Checklist

  • Code follows project conventions and style guidelines
  • Commit messages follow Conventional Commits
  • Self-review of code completed
  • Tests added/updated and passing
  • No new warnings or errors introduced
  • Changes are backward compatible

Pre-fix, target.path was the canonicalized absolute path from
Project::discover (e.g. /home/<user>/dev/agentnative-cli). That value
flows into committed scorecards under agentnative-site/scorecards/,
README badge URLs, and any agent-posted artifact — leaking three PII
vectors:

- operator username via /home/<user>/, /Users/<user>/, C:\Users\<user>\
- org/employer dir structure (e.g. /home/<user>/work/<company>/...)
- personal directory layout intent (~/dev vs ~/code etc.)

Post-fix: target.path is the basename of the resolved target — the
directory name in project mode, the file name in binary mode. Identical
identifying signal to tool.name (the slug used by /score/<slug> URLs
and badge embeds); anything richer was information leakage with no
compensating use.

Schema impact: none. target.path stays string|null; always-present-null
contract holds; no schema_version bump (the bump field marks key/shape
additions, not value-content changes).

Implementation:

- src/main.rs::build_target_info uses new basename_string() helper that
  wraps Path::file_name → to_string_lossy. Pathological paths where
  file_name() returns None (e.g. /, ..) fall back to null, consistent
  with the always-present-null contract.
- src/scorecard/mod.rs TargetInfo doc comment names the leak rationale.
- CLAUDE.md scorecard 0.4 target bullet updated with leak rationale +
  pointer to the regression-guard test.
- tests/scorecard_schema_v05.rs:
  - project mode test pins parsed["target"]["path"] == "perfect-rust"
    (was: just is_string()) — direct PII-leak guard.
  - binary mode test pins parsed["target"]["path"] == "test.sh".
  - new test schema_v05_target_path_carries_no_separators rejects any
    forward or back slash in the value — catches future regressions
    where a richer path representation might creep back in.

Verified end-to-end via dogfood on this repo:
  - project mode: "agentnative-cli" (was: /home/brett/dev/agentnative-cli)
  - binary mode: "anc" (was: full path)
  - command mode: null (unchanged)
@brettdavies
brettdavies merged commit 94f11cf into dev Apr 30, 2026
7 checks passed
@brettdavies
brettdavies deleted the fix/target-path-basename branch April 30, 2026 22:52
brettdavies added a commit that referenced this pull request May 1, 2026
…e templates (#40)

## Summary

Refresh `README.md` to match the post-v0.2.0 surface and add the
`anc.dev` agent-native badge at the top
(local TODO 019). Trim `.github/ISSUE_TEMPLATE/` to cli-scope per
`CONTRIBUTING.md` routing and add a blank-issue
fallback that sorts first in the chooser.

`anc` scores 97% against its own spec; the badge now displays the score
on the canonical README.

## Changelog

### Changed

- README refreshed for current state: schema 0.5 with `badge` block,
`--audit-profile <CATEGORY>` documented under
CLI Reference, `target.path` documented as basename-only (PII-safe),
refreshed Example Output to match the live
  33-check dogfood and the post-summary badge embed hint.

### Documentation

- Add the
`[![agent-native](https://anc.dev/badge/anc.svg)](https://anc.dev/score/anc)`
badge plus crates.io and
  license shields at the top of `README.md`.
- Trim `.github/ISSUE_TEMPLATE/` to `false-positive`, `feature-request`,
`scoring-bug`, plus a new `00-blank.yml`
that lets a Blank issue option sit first in the chooser ahead of the
structured forms. Spec-side templates
(`pressure-test`, `grade-a-cli`, `spec-question`) were duplicates of the
spec repo's set from before the
rename — they belong on `brettdavies/agentnative` only, and `config.yml`
already redirects there.

## Type of Change

- [x] `docs`: Documentation update
- [x] `chore`: Maintenance tasks (dependencies, config, etc.)

## Related Issues/Stories

- Story: n/a
- Issue: n/a (resolves local TODO
`.context/compound-engineering/todos/019-completed-p0-add-anc-badge-to-readme.md`)
- Architecture: n/a
- Related PRs: builds on #39 (basename `target.path`) and #36 (badge
embed in scorecard 0.5)

## Testing

- [x] Manual testing completed
- [x] All tests passing

**Test Summary:**

- Pre-push hook ran: fmt, clippy `-Dwarnings`, 445 unit + integration
tests, cargo-deny, Windows libc grep + cross-target clippy — all green.
- `cargo run -- check .` confirms the live 33-check dogfood reported in
the README's Example Output.
- `curl -sSI https://anc.dev/badge/anc.svg` and
`https://anc.dev/score/anc` both `HTTP/2 200`, so the embedded badge
resolves before merge.
- All four remaining issue templates parse as YAML.

## Files Modified

**Modified:**

- `README.md` — badge row, schema 0.5 / badge block, basename
`target.path`, `--audit-profile` flag, refreshed Example Output,
Contributing block fix.

**Created:**

- `.github/ISSUE_TEMPLATE/00-blank.yml` — blank-issue template that
sorts first in the chooser.

**Renamed:**

- None.

**Deleted:**

- `.github/ISSUE_TEMPLATE/grade-a-cli.yml` — moved to spec repo only.
- `.github/ISSUE_TEMPLATE/pressure-test.yml` — moved to spec repo only.
- `.github/ISSUE_TEMPLATE/spec-question.yml` — moved to spec repo only.

## Key Features

- The README's badge auto-updates from the SVG endpoint; no further
maintenance once embedded.
- Structured templates now match `CONTRIBUTING.md`'s cross-repo routing
table — no more spec-side issues filed on the cli repo by accident.

## Benefits

- Closes the credibility gap visible to anyone arriving from `anc.dev`
or a Show HN reader checking the canonical implementation.
- Reduces template-vocabulary drift between the cli repo and the spec
repo (the duplicated templates were byte-identical at branch time, but
would have drifted on the next spec-side edit).

## Breaking Changes

- [x] No breaking changes

## Deployment Notes

- [x] No special deployment steps required

## Checklist

- [x] Code follows project conventions and style guidelines
- [x] Commit messages follow [Conventional
Commits](https://www.conventionalcommits.org/)
- [x] Self-review of code completed
- [x] Tests added/updated and passing
- [x] No new warnings or errors introduced
- [x] Changes are backward compatible (or breaking changes documented)
@brettdavies brettdavies mentioned this pull request May 1, 2026
16 tasks
brettdavies added a commit that referenced this pull request May 1, 2026
## Summary

v0.3.0 promotes 15 PRs from `dev` to `main`. Headline: scorecard schema
bumps `0.3` → `0.5` (cumulative — `anc.commit` removed before tag), a
new `anc skill install <host>` subcommand with hardened `git clone` +
build-time host-map codegen, and a published agent-native badge surface
(text-mode hint + JSON `badge` block) gated on a 80% eligibility floor.
Plus PII fix on `target.path`, source-quality cleanup, README refresh,
cross-repo sync map, and tooling-side hardening (PR template
`**Renamed:**` subsection, `sync-spec` modernization,
`sync-skill-fixture` drift gate, triple-diff release-flow check with
squash-merge triage guidance).

The release-prep also surfaced four corrections that came in via the
canonical PR-to-dev flow during this ship: `#43` resynced the
`skill.json` build-time fixture against upstream `agentnative-site/dev`
(drift was blocking every open PR); `#42` corrected cross-repo URLs in
`.github/ISSUE_TEMPLATE/` (broken since the v0.1.1 squash on `main`);
`#45` replaced the release-flow's single-direction leak check with a
triple-diff plus `git cherry` patch-id check (the latter caught the URL
drift that motivated the change); `#46` added squash-merge-noise triage
guidance to the `git cherry` step (the check produced 55 noisy `+` lines
on first run, all expected, but the original comment didn't explain
that). `#47` dropped the `anc.commit` field from the scorecard JSON
before the v0.3.0 tag, since the `cargo:rerun-if-changed` `.git/`
watches made cached builds fragile and `anc.version` is sufficient build
identity.

## Changelog

<!-- Per the changelog generation rules, the canonical changelog is in
CHANGELOG.md.
This release section reflects the same content; generate-changelog.sh
extracts
from each contributing PR's ## Changelog block. The bullets below are a
     curated highlight set for the PR body itself. -->

### Added

- `anc skill install <host>` subcommand for six hosts (`claude_code`,
`codex`, `cursor`, `factory`, `kiro`, `opencode`) with `--dry-run` and
`--output {text,json}` flags and a uniform JSON envelope across success,
error, and dry-run paths (#35).
- Scorecard `--output json` self-describing metadata: four top-level
blocks (`tool`, `anc`, `run`, `target`) + a `badge` block with
`eligible`, `score_pct`, `embed_markdown`, `scorecard_url`, `badge_url`,
`convention_url` (#34, #36).
- `--output text` post-summary agent-native badge embed hint when the
tool clears the 80% eligibility floor; "do not nag" rule below (#36).

### Changed

- Scorecard `schema_version` bumped `0.3` → `0.4` → `0.5` (cumulative —
`anc.commit` field removed before the v0.3.0 tag, see #47) (#34, #36).
- `sync-spec.sh` modernized — remote-first tag resolution, `SPEC_REF`
env override removed (#33).
- `p7-naked-println` source check now exempts `build.rs` at any crate
root (#38).
- README refreshed for current state (schema 0.5, badge block,
`--audit-profile`, basename `target.path`); `rust-version` bumped `1.87`
→ `1.88` (#34, #40).
- `--output json` scorecard `anc` block no longer includes a `commit`
field — `anc.version` is the build identity (#47).

### Fixed

- `target.path` in `--output json` now emits the basename of the
resolved target instead of the canonicalized absolute path — eliminates
a home-dir / username PII leak that flowed into committed scorecards,
badge URLs, and agent-posted artifacts (#39).
- Eliminated four `.unwrap()` calls on infallible paths across
`src/skill_install.rs` and `build.rs`, replaced with `.expect("…")`
naming the contract (#38).
- Cross-repo URLs in `.github/ISSUE_TEMPLATE/` corrected: spec →
`agentnative`, site → `agentnative-site`, double-`cli` typo →
`agentnative-cli` (#42).

### Documentation

- `scripts/SYNCS.md` cross-repo sync map (#41).
- `RELEASES.md` § "After publish — sync `dev` with the release" + new
`sync-dev-after-release.sh` script formalizing the post-publish backport
convention (#37).
- `RELEASES.md` § "Releasing dev to main" step 4 replaced with a
triple-diff verification block (A: main→release, B: release→dev, C:
dev→main) plus a `git cherry` patch-id check (#45), with
squash-merge-noise triage guidance added in #46.
- README `## Install the skill` section + `[![agent-native]]` badge row
(#35, #40).

## Type of Change

- [x] `feat`: New feature (non-breaking change which adds functionality)
- [x] `fix`: Bug fix (non-breaking change which fixes an issue)
- [x] `chore`: Maintenance tasks (dependencies, config, etc.)
- [x] `docs`: Documentation update

## Related Issues/Stories

- Story: v0.3.0 release — twelve PRs across two days of work post-v0.2.0
plus four release-prep PRs (#42, #43, #45, #46) opened during the
release ceremony to fix issues caught by the new triple-diff
verification, plus #47 dropping `anc.commit` before the tag.
- Issue: n/a
- Architecture: scorecard schema evolution (`0.3 → 0.4 → 0.5`) covered
in CLAUDE.md `## Scorecard v0.5 Fields`; skill-install architecture
covered in CLAUDE.md `## Skill Install Verb`; release ceremony in
`RELEASES.md`.
- Related PRs: #30, #33, #34, #35, #36, #37, #38, #39, #40, #41, #42,
#43, #45, #46, #47 — all merged to `dev` and cherry-picked here in
chronological order.

## Testing

- [x] Unit tests added/updated
- [x] Integration tests added/updated
- [x] Manual testing completed
- [x] All tests passing

**Test Summary:**

- Unit tests: 535+ passing across all #34, #35, #36, #38, #39 PRs
(counts varied as PRs landed). #47 simplified to ~520+ after dropping
the `anc_commit_when_present_looks_like_short_sha` test.
- Integration tests: full suite green at every cherry-pick step. New
tests added: `tests/scorecard_metadata_security.rs` (red-team
regressions for hostile binaries), `tests/scorecard_schema_v05.rs`
(schema drift guard with `target.path` regression test),
`tests/skill_install.rs` (10 active + 1 ignored e2e), `tests/dogfood.rs`
(p2/p5 dogfood guards).
- Coverage: pre-push hook (CI mirror) green at every step — fmt, clippy
`-Dwarnings`, full test suite, cargo-deny, Windows compat (libc grep +
cross-target clippy).
- Triple-diff verification (the new step from #45) confirmed only
`docs/plans/`, `docs/brainstorms/`, `docs/ideation/` (guarded paths) and
the `docs/solutions` symlink remain on dev. Release-prep files
(`CHANGELOG.md`, `Cargo.{toml,lock}`, `completions/*`) will backport to
dev via `scripts/sync-dev-after-release.sh` post-publish per the
convention from #37. The `git cherry` patch-id check produced 55 `+`
lines on first run; all audited as expected (squash-merge patch-id
mismatch + conflict-resolution drift + intentional skips), zero real
misses — motivated #46's triage guidance.

## Files Modified

**Modified:**

- `Cargo.toml`, `Cargo.lock` — version `0.2.0 → 0.3.0`; `time =
"=0.3.47"` added; `rust-version` bumped.
- `CHANGELOG.md` — v0.3.0 release notes prepended.
- `README.md`, `AGENTS.md`, `CLAUDE.md` — updated for schema 0.4/0.5,
skill-install architecture, audit-profile, basename `target.path`, badge
surface, `anc.commit` removal.
- `RELEASES.md` — post-publish backport step (#37); skill-fixture sync
step; step 4 replaced with triple-diff + `git cherry` check (#45);
squash-merge triage guidance added (#46).
- `build.rs` — `emit_skill_hosts` codegen, `ANC_VERSION` emission (no
longer Git-SHA-aware after #47).
- `src/build_info.rs` — `ANC_VERSION` re-export; `ANC_COMMIT` and its
test removed in #47.
- `src/main.rs`, `src/cli.rs`, `src/error.rs`, `src/scorecard/mod.rs`,
`src/argv.rs` — schema 0.4/0.5 metadata, skill-install dispatch, badge
computation, basename helper. `AncInfo` shrinks to one field after #47.
- `src/checks/source/rust/naked_println.rs` — build.rs exemption.
- `src/skill_install/skill.json` — fixture refresh (`source.commit` pin
and `verify` block removed by upstream).
- `scripts/sync-spec.sh` — remote-first, `SPEC_REF` removed.
- `scripts/hooks/pre-push` — Windows cross-clippy step.
- `.github/pull_request_template.md` — `**Renamed:**` sub-header.
-
`.github/ISSUE_TEMPLATE/{config,false-positive,feature-request,scoring-bug}.yml`
— corrected cross-repo URLs.
- `completions/anc.{bash,zsh,fish,elvish,powershell}` — regenerated.

**Created:**

- `src/output.rs`, `src/skill_install.rs`,
`src/skill_install/skill.json`.
- `tests/dogfood.rs`, `tests/scorecard_metadata_security.rs`,
`tests/scorecard_schema_v05.rs`, `tests/skill_install.rs`,
`tests/fixtures/hostile-{hang,nonzero-exit,stdout-flood}/probe.sh`.
- `scripts/sync-skill-fixture.sh`, `scripts/sync-dev-after-release.sh`,
`scripts/SYNCS.md`.
- `.github/workflows/skill-fixture-drift.yml`.
- `.github/ISSUE_TEMPLATE/00-blank.yml`.

**Renamed:**

- `tests/scorecard_schema_v04.rs` → `tests/scorecard_schema_v05.rs`
(drift guard now covers `badge.*` keys).
- `tests/fixtures/skill.json` → `src/skill_install/skill.json` (codegen
needs to read from a path inside cargo's package).

**Deleted:**

- `.github/ISSUE_TEMPLATE/grade-a-cli.yml`, `pressure-test.yml`,
`spec-question.yml` — duplicates of the spec repo's set; routed via
`config.yml`.
- `src/build_info.rs::ANC_COMMIT` const (and its test) — dropped before
tag, see #47.

## Breaking Changes

- [x] No breaking changes

The scorecard `schema_version` bumps (`0.3` → `0.4` → `0.5`) are
additive within the documented `0.x` pre-launch policy. Pre-`0.4`
consumers feature-detect the four metadata blocks; pre-`0.5` consumers
feature-detect the `badge` key. `target.path` value semantics changed
(basename instead of absolute path) — schema shape is unchanged, so
consumers reading the field at all will continue to parse it; consumers
using it for cross-host correlation should already have migrated to
`tool.name`. `anc.commit` was added in 0.4 but removed before the v0.3.0
tag (#47); no public consumer of the field exists pre-launch.

## Deployment Notes

- [x] No special deployment steps required

Standard pipeline: tag push triggers crates.io publish (Trusted
Publishing, OIDC), GitHub Release with all 5 platform archives +
sha256sums, then dispatch to `brettdavies/homebrew-tap` for formula
update. After `finalize-release.yml` flips `make_latest: true`, run
`./scripts/sync-dev-after-release.sh v0.3.0` to backport `Cargo.toml`,
`Cargo.lock`, `CHANGELOG.md` to dev (new convention from #37).

## Checklist

- [x] Code follows project conventions and style guidelines
- [x] Commit messages follow [Conventional
Commits](https://www.conventionalcommits.org/)
- [x] Self-review of code completed
- [x] Tests added/updated and passing
- [x] No new warnings or errors introduced
- [x] Changes are backward compatible (or breaking changes documented)
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