feat(remediate): --mark-compromised + shipper fix-forward (#98 PR 3)#131
feat(remediate): --mark-compromised + shipper fix-forward (#98 PR 3)#131EffortlessSteven wants to merge 2 commits into
Conversation
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8ee0c3d17d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| fn is_compromised(p: &PackageReceipt) -> bool { | ||
| p.compromised_at.is_some() && matches!(p.state, PackageState::Published) |
There was a problem hiding this comment.
Include skipped published crates in compromised filter
build_plan currently drops any compromised package whose state is not exactly Published. That misses crates recorded as Skipped because they were already published, even though yank --mark-compromised can still mark those receipt entries and they may represent the compromised version you just yanked. In that scenario, fix-forward silently omits a real compromised crate and produces an incomplete supersession plan.
Useful? React with 👍 / 👎.
| let receipt_path = from_receipt.unwrap_or_else(|| { | ||
| opts.state_dir | ||
| .join(shipper::state::execution_state::RECEIPT_FILE) |
There was a problem hiding this comment.
Resolve default fix-forward receipt path from workspace root
The default --from-receipt path is derived directly from opts.state_dir, so a relative state dir is resolved against the current shell directory, not the workspace root used by publish/receipt generation. Running from outside the workspace (for example with --manifest-path /path/to/ws/Cargo.toml) will look up the wrong receipt.json and fail even though the workspace receipt exists.
Useful? React with 👍 / 👎.
Stitch the Remediate pillar together with a step-by-step operator guide that walks through yank --mark-compromised → fix-forward plan → publish → optional plan-yank finalize. Tied to docs/README.md's how-to index so operators can find it without folklore. Covers: - 4-step remediation flow with concrete commands - Worked example: single-CVE in a multi-crate workspace - Explicit statement of what yank does NOT do (lockfile invalidation, version bumping, consumer notification) No code changes. This only references commands added in this branch stack (#121 yank, #129 plan-yank, #131 mark-compromised + fix-forward).
4314a68 to
3d6ace0
Compare
Close the remediation staged rollout: yank (PR 1) + plan-yank (PR 2) + **fix-forward planning (this PR)** give operators the three building blocks for handling a compromised release without improvising. ## What's new ### \`shipper yank --mark-compromised\` New opt-in flag on the existing yank primitive. When set, after a successful \`cargo yank\`, shipper also amends the matching \`PackageReceipt\` in \`<state_dir>/receipt.json\` with: - \`compromised_at = Utc::now()\` - \`compromised_by = <--reason>\` These are the fields added (additively) in PR 2 (#129). The amendment lets downstream commands find compromised packages without scanning events.jsonl. Behaviour is tolerant: - No receipt → warn + proceed (yank still succeeds) - No matching package in receipt → warn + proceed - Load/write errors → warn + proceed (yank already happened; a receipt-write failure doesn't retroactively unyank) ### \`shipper fix-forward --from-receipt <path>\` New planning command. Reads a receipt, finds packages flagged \`compromised_at = Some(_)\`, and prints an ordered supersession plan: - Topological order (dependencies first, dependents last) — opposite of plan-yank, because fix-forward *publishes* replacements while plan-yank *removes* reachability. - Suggested successor versions use a placeholder format (\`<old>-next\`) so the operator picks the real bump (patch / minor / major). - Instructional preamble walks through the full remediation loop: bump Cargo.toml → commit → \`shipper publish\` → optional \`shipper plan-yank --compromised-only\` for containment. Like plan-yank, fix-forward is **planning only**. It does not edit Cargo.toml or invoke publish — those are operator steps. ## Tests 4 new tests in \`engine::fix_forward::tests\`: - only compromised+Published packages produce steps (Failed-but- compromised packages are silently dropped — they were never shipped) - topological order preserved from receipt.packages - empty plan (no compromised packages) renders with guidance toward \`--mark-compromised\` - text render enumerates steps with reason and points toward the publish + plan-yank follow-ups Plus CLI snapshots for \`yank --help\` (gains \`--mark-compromised\`) and \`fix-forward --help\`. ## Scope — explicitly NOT in this PR - **Automated Cargo.toml bump.** Workspace-edit territory; needs its own PR with --dry-run, --apply, and git-cleanliness guards. - **Publishing successors.** \`shipper publish\` already does this; fix- forward just tells the operator when to run it. - **Chaining \`superseded_by\` back to the original receipt.** Requires post-publish receipt amendment from the successor run. Follow-on. - **\`release_compromised\` top-level state.** The receipt-level marker. For now the per-package \`compromised_at\` fields cover the planning-level need.
Stitch the Remediate pillar together with a step-by-step operator guide that walks through yank --mark-compromised → fix-forward plan → publish → optional plan-yank finalize. Tied to docs/README.md's how-to index so operators can find it without folklore. Covers: - 4-step remediation flow with concrete commands - Worked example: single-CVE in a multi-crate workspace - Explicit statement of what yank does NOT do (lockfile invalidation, version bumping, consumer notification) No code changes. This only references commands added in this branch stack (#121 yank, #129 plan-yank, #131 mark-compromised + fix-forward).
7def21a to
00a79dc
Compare
Stitch the Remediate pillar together with a step-by-step operator guide that walks through yank --mark-compromised → fix-forward plan → publish → optional plan-yank finalize. Tied to docs/README.md's how-to index so operators can find it without folklore. Covers: - 4-step remediation flow with concrete commands - Worked example: single-CVE in a multi-crate workspace - Explicit statement of what yank does NOT do (lockfile invalidation, version bumping, consumer notification) No code changes. This only references commands added in this branch stack (#121 yank, #129 plan-yank, #131 mark-compromised + fix-forward).
Stitch the Remediate pillar together with a step-by-step operator guide that walks through yank --mark-compromised → fix-forward plan → publish → optional plan-yank finalize. Tied to docs/README.md's how-to index so operators can find it without folklore. Covers: - 4-step remediation flow with concrete commands - Worked example: single-CVE in a multi-crate workspace - Explicit statement of what yank does NOT do (lockfile invalidation, version bumping, consumer notification) No code changes. This only references commands added in this branch stack (#121 yank, #129 plan-yank, #131 mark-compromised + fix-forward).
…134) * feat(remediate): --mark-compromised + shipper fix-forward (#98 PR 3) Close the remediation staged rollout: yank (PR 1) + plan-yank (PR 2) + **fix-forward planning (this PR)** give operators the three building blocks for handling a compromised release without improvising. ## What's new ### \`shipper yank --mark-compromised\` New opt-in flag on the existing yank primitive. When set, after a successful \`cargo yank\`, shipper also amends the matching \`PackageReceipt\` in \`<state_dir>/receipt.json\` with: - \`compromised_at = Utc::now()\` - \`compromised_by = <--reason>\` These are the fields added (additively) in PR 2 (#129). The amendment lets downstream commands find compromised packages without scanning events.jsonl. Behaviour is tolerant: - No receipt → warn + proceed (yank still succeeds) - No matching package in receipt → warn + proceed - Load/write errors → warn + proceed (yank already happened; a receipt-write failure doesn't retroactively unyank) ### \`shipper fix-forward --from-receipt <path>\` New planning command. Reads a receipt, finds packages flagged \`compromised_at = Some(_)\`, and prints an ordered supersession plan: - Topological order (dependencies first, dependents last) — opposite of plan-yank, because fix-forward *publishes* replacements while plan-yank *removes* reachability. - Suggested successor versions use a placeholder format (\`<old>-next\`) so the operator picks the real bump (patch / minor / major). - Instructional preamble walks through the full remediation loop: bump Cargo.toml → commit → \`shipper publish\` → optional \`shipper plan-yank --compromised-only\` for containment. Like plan-yank, fix-forward is **planning only**. It does not edit Cargo.toml or invoke publish — those are operator steps. ## Tests 4 new tests in \`engine::fix_forward::tests\`: - only compromised+Published packages produce steps (Failed-but- compromised packages are silently dropped — they were never shipped) - topological order preserved from receipt.packages - empty plan (no compromised packages) renders with guidance toward \`--mark-compromised\` - text render enumerates steps with reason and points toward the publish + plan-yank follow-ups Plus CLI snapshots for \`yank --help\` (gains \`--mark-compromised\`) and \`fix-forward --help\`. ## Scope — explicitly NOT in this PR - **Automated Cargo.toml bump.** Workspace-edit territory; needs its own PR with --dry-run, --apply, and git-cleanliness guards. - **Publishing successors.** \`shipper publish\` already does this; fix- forward just tells the operator when to run it. - **Chaining \`superseded_by\` back to the original receipt.** Requires post-publish receipt amendment from the successor run. Follow-on. - **\`release_compromised\` top-level state.** The receipt-level marker. For now the per-package \`compromised_at\` fields cover the planning-level need. * docs: how-to for remediating a compromised release (#98) Stitch the Remediate pillar together with a step-by-step operator guide that walks through yank --mark-compromised → fix-forward plan → publish → optional plan-yank finalize. Tied to docs/README.md's how-to index so operators can find it without folklore. Covers: - 4-step remediation flow with concrete commands - Worked example: single-CVE in a multi-crate workspace - Explicit statement of what yank does NOT do (lockfile invalidation, version bumping, consumer notification) No code changes. This only references commands added in this branch stack (#121 yank, #129 plan-yank, #131 mark-compromised + fix-forward).
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Summary
Close the Remediate pillar's staged rollout:
What's new
`shipper yank --mark-compromised`
New opt-in flag on the existing yank primitive. Mirrors the yank into
the receipt by amending `compromised_at` / `compromised_by` on the
matching `PackageReceipt`. Tolerant to missing receipt / missing
entry — yank always wins, mark is best-effort.
`shipper fix-forward --from-receipt `
New planning command. Reads a receipt, finds packages flagged
`compromised_at = Some(_)`, prints a topologically-ordered supersession
plan — dependencies first (opposite of plan-yank, because you're
publishing replacements here, not removing reachability).
Planning only — no Cargo.toml edits, no publish invocation. Honors
`--format text|json`.
Example
```
$ shipper yank --crate app --version 0.1.0
--reason "CVE-2026-0001" --mark-compromised
[warn] yanking app@0.1.0 ...
[info] marked app@0.1.0 compromised in .shipper/receipt.json
[info] yanked app@0.1.0 successfully...
$ shipper fix-forward
fix-forward plan — registry=crates-io, plan_id=abc
1 package(s) marked compromised
Steps:
1. For each crate below, bump the version in its Cargo.toml ...
3. Run `shipper publish` to ship the successors in topo order.
4. Once all successors are live, optionally run `shipper plan-yank
--compromised-only` to contain the compromised versions.
```
Scope — explicitly NOT in this PR
Tests
Test plan
Closes
Once this + #121 + #129 land, issue #98 Remediate is complete at the planning/primitive level. Cargo.toml edits and successor chaining are clean follow-ons.