Skip to content

chore: comprehensive publish hardening - #90

Merged
developer0hye merged 1 commit into
mainfrom
chore/security-hardening
Apr 28, 2026
Merged

chore: comprehensive publish hardening#90
developer0hye merged 1 commit into
mainfrom
chore/security-hardening

Conversation

@developer0hye

Copy link
Copy Markdown
Owner

Summary

Layered defenses against the v1.2.1 leak class. Each layer is independent — disabling any one still leaves the others holding.

# Layer What Where
1 Cargo.toml whitelist include = ["src/**/*.rs", "/LICENSE", "/README.md"] — published surface is now exactly source code + license + readme + cargo's auto files. Anything else cannot leak. Cargo.toml
2 .gitignore extensions IDE/editor state (.vscode/, .cursor/, .idea/), swap/backup files, build/coverage artifacts, and a categorical credential block (*.pem, *.key, id_rsa*, *credentials*, *secrets*) .gitignore
3 .dockerignore parity .omc/, .env, .env.* so COPY . . can't bake them into a future container image .dockerignore
4 CI secret scan gitleaks/gitleaks-action@v2 over full git history — would have caught v1.2.1 before publish ci.yml (new security job)
5 CI dependency audit cargo audit for known RUSTSEC advisories; continue-on-error: true so advisory churn doesn't block unrelated PRs same job
6 CI publish audit cargo package --list piped through a sensitive-pattern grep; CI fails before crates.io ever sees a leak. Belt and suspenders for Layer 1 same job

Package contents diff

Drops these dev-only files from the published crate (none used by consumers):

  • Dockerfile, docker-compose.yml, .dockerignore
  • .github/ (CI configs, issue templates)
  • AGENTS.md, CLAUDE.md, TECH_SPEC.md
  • .gitignore
  • tests/ (test code + binary fixtures)

After this PR, cargo package --list returns 35 files: src/**/*.rs (29 source files) + Cargo.toml/Cargo.lock/Cargo.toml.orig/.cargo_vcs_info.json + LICENSE + README.md.

Test plan

  • cargo package --list --allow-dirty — exactly the 35 expected files; sensitive-pattern grep matches nothing
  • cargo build && cargo test && cargo clippy -- -D warnings && cargo fmt --check all green
  • CI passes on PR (gitleaks should be green — no secrets in tree; cargo audit may surface advisories but is non-blocking; publish audit will assert)

🤖 Generated with Claude Code

Layered defenses against the v1.2.1 leak class. Each layer is
independent — a future maintainer can disable any one of them and
the others still hold.

Layer 1 — Cargo.toml whitelist (`include` instead of `exclude`):
The package now ships only `src/**/*.rs`, `LICENSE`, `README.md`,
and the metadata files cargo always auto-includes (`Cargo.toml`,
`Cargo.lock`, `Cargo.toml.orig`, `.cargo_vcs_info.json`). Anything
else — `.env`, `.omc/`, `.claude/`, IDE state, dev docs, CI
configs — cannot leak by accident, because adding new files no
longer expands the publish surface unless someone explicitly lists
them. Drops `Dockerfile`, `docker-compose.yml`, `.dockerignore`,
`.github/`, `AGENTS.md`, `CLAUDE.md`, `TECH_SPEC.md`, `tests/`,
`.gitignore` from the published crate (none used by consumers).

Layer 2 — `.gitignore` extensions:
Adds editor/IDE state (`.vscode/`, `.cursor/`, `.idea/`), swap and
backup files (`*.swp`, `*.swo`, `*~`, `*.bak`), build/coverage
artifacts (`*.log`, `coverage/`, `*.profraw`, `lcov.info`,
`tarpaulin-report.html`), and a categorical credential block
(`*.pem`, `*.key`, `id_rsa*`, `id_ed25519*`, `*credentials*`,
`*secrets*`). Categorical because new file names matching these
shapes are almost always sensitive.

Layer 3 — `.dockerignore` parity:
Adds `.omc/`, `.env`, `.env.*` so `COPY . .` in the Dockerfile
cannot bake them into image layers if anyone later publishes the
container.

Layer 4 — CI secret scan (gitleaks):
New `security` job runs `gitleaks/gitleaks-action@v2` against the
full history on every push/PR. Free for public repos. Would have
caught the v1.2.1 leak before publish.

Layer 5 — CI dependency audit (cargo-audit):
Same job runs `cargo audit` for known RUSTSEC advisories.
Marked `continue-on-error: true` so a fresh advisory doesn't block
unrelated PRs but still surfaces in the run log.

Layer 6 — CI publish-package audit:
Same job runs `cargo package --list` and greps for sensitive
patterns; CI fails before crates.io ever sees a leak. Belt and
suspenders for Layer 1 — even if `include` is later loosened, this
still catches additions matching the patterns.

Verified locally:
- `cargo package --list` shows the 35 expected files (no
  Dockerfile / .github / CLAUDE.md / tests / etc).
- Sensitive-pattern grep against the package list returns nothing.
- `cargo build && cargo test && cargo clippy -- -D warnings &&
  cargo fmt --check` all green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Yonghye Kwon <developer.0hye@gmail.com>
@developer0hye
developer0hye merged commit 9f6179c into main Apr 28, 2026
7 checks passed
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