Skip to content

Feat/hardening p0 p2 - #9

Merged
S1933 merged 6 commits into
mainfrom
feat/hardening-p0-p2
Jul 13, 2026
Merged

Feat/hardening p0 p2#9
S1933 merged 6 commits into
mainfrom
feat/hardening-p0-p2

Conversation

@S1933

@S1933 S1933 commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added doctor health checks for installation, permissions, snapshots, and target directories.
    • Added explain to preview generated files for a selected target.
    • Added JSON output support for diff and push.
    • Improved interrupted push recovery and atomic file updates.
    • Added race-enabled testing and vulnerability scanning commands.
  • Documentation

    • Expanded command documentation and clarified JSON output and OpenCode synchronization behavior.
  • Bug Fixes

    • Improved consistency and reliability of generated configuration across supported targets.

Jean-Philippe Déïs Nuel and others added 6 commits July 13, 2026 22:44
Robustness and correctness pass before a stable release:

- CI: run tests with -race -shuffle=on; add govulncheck step.
- CI: replace unpinned golangci-lint master install with
  golangci-lint-action@v8 (golangci-lint v2.12.2); pin checkout and
  setup-go actions by commit SHA.
- Add .golangci.yml v2 config (standard linters + std-error-handling
  preset) so the enabled set does not drift with tool upgrades.
- Bump toolchain to Go 1.25.12 and go-git v5.19.1, x/crypto v0.52.0,
  x/net v0.54.0 — clears all 38 code-reachable vulnerabilities to 0.
  (go-git v5.19.1 requires Go >= 1.25.)
- Docs: correct the OpenCode prune description. The behavior is
  asymmetric — the package apply flow prunes owned nested entries via
  ManagedPruner, while `shenron push` stays upsert-only because it does
  not record per-leaf ownership.
- Tests: add TestEndToEnd_PushAllTargetsIdempotent asserting every
  adapter reports "No changes" after a full push.
- Tests: add FuzzMergeFile covering no-panic, valid-JSON output,
  foreign-key preservation, and idempotence of the OpenCode merge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-1.3)

Harden the adapter boundary per the audit's P1 items:

- P1.1: introduce adapter.GeneratedFile{Path,Content,Mode,Adapter,
  ResourceID} and GenerationResult{Files,Fragments}. The file mode now
  flows through to fsutil.WriteFileAtomic instead of a hardcoded 0o644.
- P1.2: remove mutable adapter state. Both OpenCode (fragments) and
  Codex (nativeNames — a case the audit missed) built cross-resource
  state on the receiver and needed a reset between passes. Generation is
  now a single Generate(*pivot.PivotFile) pass that builds everything in
  local variables, so adapters are reentrant and safe to reuse. Drops
  ResetFragments/Fragments. Adds a reentrancy regression test.
- P1.3: formalize optional behaviors as capability interfaces in
  capabilities.go — MergingAdapter, ManagedPruner, PivotDirectoryAware.
  MergeFile leaves the base Adapter interface; the nil-returning stubs on
  Claude and Codex are gone, as are the duplicate private interfaces that
  cli/sync.go declared.

Generate (cli) now returns map[string][]adapter.GeneratedFile; the diff
engine still consumes a path->content projection, while the push writer
uses each file's mode.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…(P1.4)

Make the multi-file push atomic and crash-recoverable:

- Add fsutil.Transaction: Stage writes each file to a temp file in its
  destination directory; Commit journals the pending renames to
  .shenron-journal.json, performs them, then removes the journal. If a
  rename fails partway, the journal is left for recovery.
- Add fsutil.RecoverTransaction: replays a leftover journal's pending
  renames (roll-forward) and removes it. runPushAt runs recovery at
  startup, before reading on-disk state, so a push interrupted after its
  journal was written completes on the next run.
- runPushAt now stages every changed file and commits the batch as one
  transaction instead of renaming file-by-file, so a failure mid-batch
  leaves nothing applied.

The write batch is now all-or-nothing. Updated the interrupt test to
assert atomic semantics (no file committed when the batch fails) while
keeping its core invariant: Managed is persisted before writes, so a
re-push never collides on the package's own opencode.json entries.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add `--output json` to the diff and push commands (default text). The
runtime separates computation from rendering:

- report.go defines DiffReport / PushReport with per-file {path, adapter,
  status, resourceId} entries plus orphaned paths, and builds them from
  the existing diff results.
- runDiffAt/runPushAt take an output format; the text path is unchanged,
  the JSON path emits a report to stdout.
- In JSON mode, stdout carries only the report; permission/skill
  preambles and orphan warnings are routed to stderr so the stream stays
  parseable.

Adds end-to-end tests for both reports and for rejecting an unknown
format, and documents the flag in the README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduce a read-only `doctor` command that inspects the environment and
every installed package:

- target adapter config paths, flagging any whose nearest existing
  ancestor is not writable;
- each installed package's snapshot digest (cache integrity, via Load),
  its sync-state file (must parse), and its permission-approval status
  (pending approval is a warning).

Supports --output json (DoctorReport) alongside the default text; exits
non-zero (ErrDoctorFailed) when any check fails. Warnings do not fail the
run. Documented in the README command table.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduce a read-only `explain <name> --target <tool>` command that shows
the native files a package translates into for one target, computed from
the pivot alone (ignoring on-disk state) so it answers "what does this
package become for target X?".

- Runs the target adapter's Generate over the package pivot; for merging
  adapters it also folds the fragments into a fresh config (empty host),
  so the opencode.json translation is shown with no foreign entries.
- Each entry is labelled with the pivot resource it came from
  (GeneratedFile.ResourceID), which P1.1 now carries end to end.
- Supports --output json (ExplainReport) alongside text. Requires
  --target; rejects unknown targets.

Documented in the README command table.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: be717c1c-f2f3-447c-8611-ac40a7a54ccd

📥 Commits

Reviewing files that changed from the base of the PR and between 92c19a0 and 625a057.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (30)
  • .github/workflows/ci.yml
  • .golangci.yml
  • Makefile
  • README.md
  • docs/ARCHITECTURE.md
  • go.mod
  • internal/adapter/adapter.go
  • internal/adapter/capabilities.go
  • internal/adapter/claude/adapter.go
  • internal/adapter/claude/adapter_test.go
  • internal/adapter/codex/adapter.go
  • internal/adapter/codex/adapter_test.go
  • internal/adapter/opencode/adapter.go
  • internal/adapter/opencode/adapter_test.go
  • internal/adapter/opencode/fuzz_test.go
  • internal/cli/commands_test.go
  • internal/cli/doctor.go
  • internal/cli/doctor_test.go
  • internal/cli/explain.go
  • internal/cli/explain_test.go
  • internal/cli/package.go
  • internal/cli/package_apply.go
  • internal/cli/package_test.go
  • internal/cli/report.go
  • internal/cli/sync.go
  • internal/cli/sync_runtime.go
  • internal/cli/sync_test.go
  • internal/fsutil/journal.go
  • internal/fsutil/journal_test.go
  • internal/integration_test.go

📝 Walkthrough

Walkthrough

The change unifies adapter generation around generated-file records, adds doctor and explain commands, introduces JSON output for diff and push, adds recoverable journaled writes, and updates CI, linting, Go dependencies, documentation, and validation tests.

Changes

Sync and CLI evolution

Layer / File(s) Summary
Toolchain and validation setup
.github/workflows/ci.yml, .golangci.yml, Makefile, go.mod
CI and local targets add race testing and vulnerability scanning, while Go and dependency versions are updated.
Unified adapter generation
internal/adapter/*
Adapters now return GeneratedFile and GenerationResult values through a unified Generate method with optional capabilities for merging, pruning, and pivot-directory awareness.
Doctor and explain commands
internal/cli/doctor.go, internal/cli/explain.go, internal/cli/package.go, internal/cli/*_test.go
Adds package health checks, target-native generation previews, JSON/text rendering, command registration, and coverage for both commands.
Generated-file sync and structured reports
internal/cli/package_apply.go, internal/cli/report.go, internal/cli/sync.go, internal/cli/sync_runtime.go, README.md, docs/ARCHITECTURE.md
Sync and package flows consume generated-file records, support JSON diff/push output, apply OpenCode ownership behavior, and document the updated commands and merge policy.
Recoverable push transactions
internal/fsutil/journal.go, internal/fsutil/journal_test.go, internal/cli/sync_runtime.go, internal/cli/package_test.go, internal/integration_test.go
Pushes stage writes through a journaled transaction, recover interrupted renames, and validate atomicity, idempotence, JSON output, and invalid formats.

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

Possibly related PRs

  • S1933/Shenron#2: Introduced the package and diff/push CLI flows extended by this change.
  • S1933/Shenron#6: Covered related OpenCode ownership, pruning, and push mechanics.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/hardening-p0-p2

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.

@S1933
S1933 merged commit d70e016 into main Jul 13, 2026
1 of 2 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