Skip to content

Protect whole-server pushes from overwriting newer client edits - #44

Merged
elemdos merged 2 commits into
masterfrom
fix/push-conflict-guard
Sep 29, 2026
Merged

elemdos merged 2 commits into
masterfrom
fix/push-conflict-guard

Conversation

@elemdos

@elemdos elemdos commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Stop a whole-server push before any uploads when a client changed a site or shared library since the last successful pull/push. Allow an intentional overwrite with explicit confirmation and server-created backups.

  • Persist server/target-scoped revisions from export/import responses. Missing baselines on existing targets fail closed; never bless a separately fetched, newer revision.
  • Preflight every included target, then send the checked revision with each import. A late conflict stops remaining uploads and reports completed, failed, and unattempted targets.
  • Add --force and --yes for normal and standalone library pushes. Force uses the preflight revision, downloads backups, and cannot bypass an unsupported server.
  • Preserve export-time site metadata during pull. Replace the pulled library exactly, keeping its previous local copy in .primo/trash, so deleted server blocks cannot be resurrected under a fresh baseline.
  • Keep preview read-only, including the library, and prevent existing unauthenticated sites from falling back to bootstrap.

Validation: TypeScript build and all 71 CLI tests passed with PRIMO_TEST_CMS_BINARY set to the companion CMS build. Tests include stale later sites/library, no baseline, unsupported servers, explicit confirmation, force followed by ordinary push, partial-success reporting, legacy pulls, deleted sites, and a real two-site/shared-library CMS round trip.

Requires the companion CMS protocol update. Update CMS and CLI together, then pull to establish baselines. A conflict never pulls or merges automatically. Backups are private ZIP exports with original records; recovery of fields unsupported by the portable importer may require operator assistance. Push still updates CMS content without automatically publishing the website.

Companion CMS change: primocms/primo#1263

Summary by CodeRabbit

  • New Features
    • Pushes now check for server-side changes before uploading and stop when saved revision information is missing or out of date.
    • Use --force to overwrite server changes after confirmation; add --yes to confirm without an interactive prompt. Overwrites require a server backup.
    • Workspace pushes preflight selected targets and stop at the first failure. Use --only to limit a push to one site.
    • Pulls save revision information to help protect future pushes.

@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 36d41bd8-6e5b-4aa8-8cbb-3f1fec02f22e

📥 Commits

Reviewing files that changed from the base of the PR and between 9392cfc and fd54daa.

📒 Files selected for processing (12)
  • README.md
  • src/commands/pull-library.ts
  • src/commands/pull.ts
  • src/commands/push-library.ts
  • src/commands/push.ts
  • src/index.ts
  • src/utils/pull-library-export.ts
  • src/utils/push-guard.ts
  • tests/helpers/mock-server.mjs
  • tests/push-cms.test.mjs
  • tests/push-guard.test.mjs
  • tests/smoke.test.mjs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Pulls now record site and library revisions as local baselines. Pushes preflight selected targets, send expected revisions with imports, and support confirmed forced overwrites with backups.

Changes

Revision-guarded push workflow

Layer / File(s) Summary
Capture revisions during pulls
src/commands/pull.ts, src/commands/pull-library.ts, src/utils/pull-library-export.ts, tests/push-guard.test.mjs, tests/smoke.test.mjs
Site and library pulls save export revisions as local baselines. Tests cover modern and legacy exports and set a baseline for the smoke-test push.
Plan and validate push targets
src/utils/push-guard.ts, src/commands/push.ts, src/index.ts, README.md, tests/push-guard.test.mjs
Push planning checks server revisions against saved baselines before uploads. The CLI adds --force and --yes. Tests cover stale baselines, --only, confirmation, and unsupported servers.
Run guarded imports and save results
src/commands/push.ts, src/commands/push-library.ts, src/utils/push-guard.ts, tests/helpers/mock-server.mjs, tests/push-guard.test.mjs, tests/push-cms.test.mjs, README.md
Site and library imports include expected revisions. Successful responses save new baselines, and forced overwrites process backup references. Workspace uploads stop at the first failure. Tests cover import responses, late conflicts, and backup creation.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant PushCLI
  participant prepare_push
  participant PrimoServer
  participant finish_push
  PushCLI->>prepare_push: Prepare target plans
  prepare_push->>PrimoServer: Fetch push state
  PrimoServer-->>prepare_push: Return target revisions
  prepare_push-->>PushCLI: Return validated plans
  PushCLI->>PrimoServer: Submit guarded import
  PrimoServer-->>PushCLI: Return revision and backup
  PushCLI->>finish_push: Save revision and process backup
Loading

Merge Risk: ⚪ Minimal · up to fd54d

Pushes now check each site and the shared library against the last pulled or pushed server revision. They stop before overwriting newer server edits unless you confirm a forced overwrite, which creates backups. No blocking defects were found. The CMS must be updated alongside the CLI, and each workspace should be pulled once to establish baselines before pushing.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to fd54d

Revision checks and stop-on-conflict behavior reduce accidental overwrites, but the workspace library path loses a previous authentication check, and forced-overwrite recovery can be reported as failed after the new revision has already been trusted. The server-side safeguards needed to complete this design are not available for verification.

Retained concerns

  • Medium · security · observed: Workspace library pushes can now send an import without the token previously required by that command. Whether this becomes an unauthorized write depends on CMS-side authentication, which is not available for verification.
  • Medium · reliability · observed: A forced overwrite's returned revision becomes the trusted local baseline before its backup reference is checked. A missing or invalid reference then reports failure despite the advanced baseline, weakening the recovery signal for an already-applied overwrite.
Security review details

Security Blast Radius

  • inferred — Each push targets a selected CMS site or shared library; a workspace command can process multiple sites and then the library, making partial completion and library-import authority material to the exposure.

Security Findings and Attack Paths

  • observed — With no library token, the workspace path can send a library archive without an Authorization header; the prior workspace path rejected that request locally. The available evidence does not establish that the production CMS accepts it.

Trust Boundaries and Controls

  • observed — The client sends the checked revision even with force, blocks stale ordinary pushes, and does not upload when preflight fails. CMS-side authentication, atomic comparison, and backup creation remain unverified.

Resilience and Maintainability Implications

  • observed — A missing forced-overwrite backup reference is detected only after baseline persistence; a failed backup download instead warns and retains the server URL.

Hardening Proposals

  • proposed — Preserve the workspace library authentication precondition and verify that the companion CMS authenticates imports, atomically compares revisions even under force, and creates backups before committing existing-target overwrites.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.05% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 21 functions across 11 files. (1 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: preventing whole-server pushes from overwriting newer client edits.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 19.05% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 21 functions across 11 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@elemdos
elemdos marked this pull request as ready for review September 29, 2026 17:09
@elemdos
elemdos merged commit 938b39f into master Sep 29, 2026
2 checks passed
@elemdos elemdos mentioned this pull request Sep 30, 2026
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