Repository navigation
Git That Shit v0.3.0 — final security hardening - #1
Merged
Merged
Conversation
Recover development history by merging origin/master into the recovered
local commit and commit the recovered tests.
Engine fixes:
- restore: execute exactly once, fully inside the lock; report conflicts;
never silently overwrite user changes; pre-restore snapshot no longer
blocks on no-changes
- snapshot: protect the entire operation with one exclusive project lock
- lock: atomic exclusive-create acquisition (no read-then-write TOCTOU);
ownership-checked release and stale-lock removal
- security: redact global OpenCode config; text/PEM/authorization redaction;
fail closed on unprocessable content; reject path traversal
- paths: canonical layout documented with legacy migration
- version: read packaged version instead of hardcoding
- prune: real, guarded history rewrite with safety bundle; preview default
OpenCode V2 migration:
- @opencode/plugin 2.0.21, Plugin.define({ id, setup })
- all eight gts_* tools via ctx.tool.transform with JSON Schema inputs
- execute.before for pre-op/pre-edit; event stream for session.created,
session.compaction.ended, filesystem.changed; cleanup on unload
Testing: 274 tests across 19 files (concurrency, restore, prune, security,
CLI, packaging, V2 plugin surface). CI runs typecheck/lint/build/test.
Packaging: ESM, type declarations, dist no longer committed, reduced deps.
Docs: README, CHANGELOG 0.3.0, docs/ARCHITECTURE, docs/SECURITY, docs/INTEROP
…ed files
Runtime validation against an isolated OpenCode 2.0.21 server and a local
OpenAI-compatible mock provider surfaced two real defects:
- filesystem.changed is NOT emitted for agent tool writes, so post-edit
snapshots were missed. Post-edit is now driven by
ctx.tool.hook("execute.after") on a completed edit tool; filesystem.changed
is retained as a debounced fallback for out-of-band changes.
- Restoring a snapshot would have written [REDACTED] placeholders over live
config files, destroying real secrets. Restore now always skips redacted
files and reports them.
Adds execute.after and redaction-safe restore tests (278 tests total) and
documents the verified hook mapping.
Audit + hardening so Git That Shit works alone and in any companion combination with no ordering assumptions and no shared framework. - Failure isolation: wrap execute.before/execute.after and every subscribed event in a safe() guard so a snapshot error, malformed project file, or absent companion can never surface as a tool failure or affect other plugins. - Hooks are read-only with respect to the tool event (never mutate event/input). - Documented and verified (OpenCode 2.0.21) that async execute.before is awaited before the tool runs, so pre-operation snapshots are genuinely blocking. - Added tests/independence.test.ts (9 tests): no cross-plugin imports, no companion installed, read-only hooks, malformed companion data, no writes into companion storage, reload/multi-setup isolation, malformed-event stream resilience, namespaced config/storage. - Docs: independence standard, companion matrix, companion-absent behavior, optional read-only interop surface, and Docker Plugin Test Lab compatibility. Removed order-dependent phrasing. 287 tests / 20 files.
Snapshot failure safety
- Add SnapshotResult.verified: a snapshot is only reported as existing when
its commit is confirmed to resolve in the shadow repository.
- Add snapshot.failureMode ("standard" default, "strict" opt-in) via a new
engine/safety module. Standard continues with a clear warning and never
claims a recovery point; strict denies classified destructive operations
only, through the OpenCode V2 permission.evaluate gate, and fails open with
an explicit warning when the SDK exposes no gate.
- Add snapshot.gitTimeoutMs to bound shadow-repository git subprocesses.
- Treat no-changes as an existing recovery point in the plugin (matching
restore) instead of a failure.
- Redact command previews, manual messages and error strings before they can
reach the commit message, manifest, result object or logs.
Filesystem permissions and secret protection
- New shared/permissions module: 0700 directories and 0600 files for Git That
Shit storage (config, manifest, lock, snapshot copies, prune bundles),
applied after mkdir without recursing into user project directories.
- Doctor reports storage permissions and warns on group/other access.
Restore security
- Refuse symlinked destinations and destinations whose nearest existing
ancestor resolves outside the project.
- Write atomically via an O_EXCL|O_NOFOLLOW temp file + rename so a symlink
cannot be substituted between validation and writing; clean up temp files on
failure.
- Strict mode refuses a restore whose pre-restore snapshot cannot be created;
standard mode continues with a warning and claims no recovery point.
Tests and docs
- 35 new regression tests (321 -> 322 total) covering failure injection,
permissions, restore adversarial cases and strict-mode blocking.
- Update README, ARCHITECTURE, SECURITY, INTEROP and add RELEASE-0.3.0 audit.
- Restore GIT_THAT_SHIT_GLOBAL_CONFIG_DIR in afterAll so the new test files cannot leak isolation into another file (CI caught this in tests/paths.test.ts). - Make paths' default-config-path assertion robust to a leaked override. - Raise the suite-wide Bun test timeout to 30s in bunfig.toml so subprocess-heavy tests do not flake on slow CI runners; no assertion is weakened.
… project docs Distribution and documentation changes only; no source, engine, plugin or test logic is modified, and the verified commit 6069f91 remains intact. - Add the unmodified Apache-2.0 LICENSE (package and README already declared Apache-2.0 but no licence text was shipped) and a NOTICE attribution file; include NOTICE in the published artifact. - Gate the npm publish workflow to manual workflow_dispatch so publishing a GitHub release can never trigger an automatic npm publish. - Record the non-npm distribution state in the README installation section. - Add the canonical project documents (PRODUCT_REQUIREMENTS.md, DECISION_LOG.md, PROJECT_STATUS.md) and docs/RELEASE-0.3.0-EVIDENCE.md, which pins the repository suite and the independent Docker Plugin Test Lab run to the verified commit.
gitdamnit
marked this pull request as ready for review
October 17, 2026 00:34
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
gitdamnit
added a commit
that referenced
this pull request
Oct 17, 2026
Documentation only. Records the durable release result now that PR #1 has merged and the GitHub release is published: - PROJECT_STATUS.md: phase Released; post-release verification entries (merge commit, tag, released source archive); npm publication recorded as Blocked. - docs/RELEASE-0.3.0-EVIDENCE.md: section 5 pins the released commit, tag, release URL, archive sha256 and the fresh-build verification. The release tag v0.3.0 remains at c752e58; this commit does not alter it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Git That Shit v0.3.0 — final security hardening
Focused hardening and release-readiness work on top of the existing v0.3.0 development branch. No architectural rewrite;
the shadow-git design, CLI and V2 plugin surface are unchanged.
1. Snapshot failure safety
SnapshotResult.verified— a snapshot is only reported as existing when its commit is confirmed to resolve in theshadow repository (
git rev-parse --verify <hash>^{commit}). Callers key protection offverified, never offcommittedalone.snapshot.failureMode(standarddefault,strictopt-in), implemented in the newsrc/engine/safety.ts:claimed.
git reset --hard,git clean -fd,rm -rf) via the OpenCode V2permission.evaluategate when their protective snapshot fails.Risky package-manager operations, config writes and harmless commands are never blocked.
snapshot.gitTimeoutMsbounds shadow-repository git subprocesses; a timeout is a structured failure.no-changesis treated as an existing recovery point (matching restore) rather than a failure.manifest, a result object or a log line.
Strict-mode limitation (documented, not hidden).
execute.beforereturnsvoidand cannot veto a tool; onlypermission.evaluatecan, and the SDK does not specify hook ordering. Strict tool-call blocking is thereforebest-effort and fails open with an explicit warning when no gate is exposed. The restore path's strict check is
guaranteed, because Git That Shit owns it. Runtime confirmation against a live OpenCode host was not possible in the
isolated environment; the gate is verified against the published 2.0.21 types and the V2 harness.
2. Filesystem permissions and secret protection
src/shared/permissions.ts:0700directories and0600files for Git That Shit's own storage — config,manifest, lock, snapshot copies and prune bundles — applied after
mkdirso umask cannot widen them. Only.git-that-shit/is touched; user project files and unrelated directories are never chmod'ed.chmoddegrade safely to a no-op.gts doctorreports storage permissions and warns on group/other access.3. Restore security
realpathand require it to stay within the real project root, so asymlinked directory cannot redirect a write outside the project.
O_EXCL|O_NOFOLLOWsibling temp file +rename, closing the validate-then-write symlinksubstitution window. Temp files are removed on failure.
force); overwriting a conflict still requiresforce; dry-runremains the default; restores remain under the project lock.
warning and claims no recovery point.
4. Plugin independence
Re-verified: no
@gitdamnit/*/ Stranger Danger / Checkpoint Orchestrator / CheapCode imports insrc/; the onlyruntime dependency remains
@opencode/plugin; secret handling and snapshots are self-contained; hooks do not assume anexecution order; state stays under
.git-that-shit/; the project lock serializes concurrent sessions.Validation
Clean
npm ci, typecheck, lint, build, fullbun testsuite (322 passing / 0 failing across 24 files, 35 newtests), CLI smoke tests,
npm packvalidation, and an installed-package import test. All tests are hermetic (isolated/tmpprojects and isolated config dirs); no live provider credentials were used.Documentation
Updated
README.md,docs/ARCHITECTURE.md,docs/SECURITY.md,docs/INTEROP.md,CHANGELOG.md, and addeddocs/RELEASE-0.3.0.mdwith the full audit findings and remaining limitations.