@yadsh/dsh-git-readonly 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +3 -1
  2. package/package.json +5 -5
  3. package/SPEC.md +0 -160
package/README.md CHANGED
@@ -43,8 +43,10 @@ branch → history → blame → commit — without ever receiving a command lin
43
43
 
44
44
  ## Installation
45
45
 
46
+ Install the published npm package by name:
47
+
46
48
  ```bash
47
- dsh plugin add @yadsh/dsh-git-readonly
49
+ dsh plugin --profile <profile> add @yadsh/dsh-git-readonly
48
50
  ```
49
51
 
50
52
  The plugin has no web-client surface; a host restart (or bundle reload)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yadsh/dsh-git-readonly",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Read-only git provenance tools for DeepSeek Harness agents",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,7 +27,6 @@
27
27
  "cordis.patch.yml",
28
28
  "compatibility.json",
29
29
  "README.md",
30
- "SPEC.md",
31
30
  "LICENSE"
32
31
  ],
33
32
  "dsh": {
@@ -36,7 +35,7 @@
36
35
  }
37
36
  },
38
37
  "dependencies": {
39
- "@yadsh/dsh-plugin-log": "^0.2.1"
38
+ "@yadsh/dsh-plugin-log": "^0.3.0"
40
39
  },
41
40
  "peerDependencies": {
42
41
  "@deepseek-ai/dsh-tools": ">=0.1.5-rc.2 <0.2.0",
@@ -49,8 +48,8 @@
49
48
  "eslint": "10.9.1",
50
49
  "typescript": "^7.0.2",
51
50
  "vitest": "^4.1.11",
52
- "@yadsh/dsh-test-kit": "^0.1.0",
53
- "@yadsh/dsh-config": "^0.0.0"
51
+ "@yadsh/dsh-config": "^0.0.0",
52
+ "@yadsh/dsh-test-kit": "^0.1.0"
54
53
  },
55
54
  "publishConfig": {
56
55
  "access": "public",
@@ -64,6 +63,7 @@
64
63
  "deepseek-harness",
65
64
  "dsh",
66
65
  "dsh-plugin",
66
+ "cordis",
67
67
  "git",
68
68
  "read-only",
69
69
  "provenance",
package/SPEC.md DELETED
@@ -1,160 +0,0 @@
1
- # SPEC: @yadsh/dsh-git-readonly
2
-
3
- Read-only git provenance tools for DeepSeek Harness agents.
4
-
5
- ## 1. Product contract
6
-
7
- 1. An agent whose session has a working directory can learn, in one tool
8
- call, which repository it is in (`dsh_git_context`): work-tree root,
9
- branch or detached state, upstream, HEAD id, last commit author/date and
10
- subject, and decorated refs.
11
- 2. An agent can find the commit that introduced or removed a literal string
12
- (`dsh_git_history` with `search: "content"`), locate commits by
13
- commit-message substring, author, path or ref scope, and page through
14
- the results with an explicit `truncated` marker.
15
- 3. An agent can attribute any line of a repository file to the commit that
16
- last changed it (`dsh_git_blame`), optionally in a line window and at a
17
- historical revision, and then inspect that commit (`dsh_git_show`):
18
- metadata, parents, per-file line counts, and a bounded patch.
19
- 4. The model never supplies a command line, a git option, or a git
20
- subcommand. Every argument is one of: a hexadecimal commit id
21
- (`/^[0-9a-fA-F]{7,64}$/`), a repository-relative path without `..`
22
- segments, a bounded literal search string, or a numeric limit.
23
- 5. The commit passed to `dsh_git_show` / `dsh_git_blame` is canonicalized
24
- by git itself (`rev-parse --verify --end-of-options <oid>^{commit}`)
25
- before use; only commits that exist resolve.
26
- 6. No tool call mutates the repository: refs, index, config and work tree
27
- are byte-identical before and after every call (proven by tests, §9).
28
- 7. A hostile repository cannot execute helpers through a read:
29
- `diff.external`, textconv drivers and `core.fsmonitor` configured in the
30
- inspected repository are never invoked (proven by tests, §9).
31
- 8. A poisoned ambient environment (`GIT_DIR`, `GIT_WORK_TREE`,
32
- `GIT_INDEX_FILE`, `GIT_OBJECT_DIRECTORY`, `GIT_EXTERNAL_DIFF`,
33
- `GIT_CONFIG_*`, askpass/ssh keys) cannot redirect a read; those keys are
34
- removed per invocation and deterministic values are forced.
35
- 9. Without a session working directory, or outside a git work tree, every
36
- tool fails closed with a typed error; there is no fallback to the host
37
- process cwd.
38
- 10. One call is bounded: timeouts (default 15 s, hard clamp 1–30 s), byte
39
- caps for patches (default 200 KiB) and stdout, page sizes for history
40
- (default 20, max 100) and blame lines (default 300). Exceeding a cap
41
- yields `truncated: true`, never a hang or an unbounded answer.
42
-
43
- ## 2. Surface
44
-
45
- | Tool | Parameters (model-facing) | Result |
46
- | --- | --- | --- |
47
- | `dsh_git_context` | — | root, branch?, detached, upstream?, head?, shortOid?, author?, authoredAt?, subject?, refs[] |
48
- | `dsh_git_history` | path?, query?, search?, author?, limit?, offset?, all? | commits[] {oid, shortOid, author, authoredAt, subject, refs[]}, count, truncated |
49
- | `dsh_git_show` | oid (required), path?, statOnly? | oid, shortOid, author, authoredAt, subject, body, parents[], files[] {path, additions?, deletions?}, patch, patchTruncated |
50
- | `dsh_git_blame` | file (required), fromLine?, toLine?, oid? | file, fromLine, toLine, lines[] {line, oid, author, authoredAt, summary, content}, truncated |
51
-
52
- Errors carry stable codes: `no-session-cwd`, `not-a-git-repository`,
53
- `invalid-oid`, `invalid-path`, `invalid-argument`, `git-timeout`,
54
- `git-failed`.
55
-
56
- ## 3. Data flow
57
-
58
- ```
59
- model → tools.execute(args, exec)
60
- │ validateCommitOid / validateRepoRelativePath / validateSearchLiteral
61
- │ requireSessionCwd(exec.agent.session.header.cwd) ← fail-closed
62
- │ resolveRepositoryRoot: git rev-parse --show-toplevel
63
-
64
- runGit(argv, {cwd, timeoutMs, maxBytes})
65
- │ argv = [program, …prefix, --no-pager, -c core.fsmonitor=false,
66
- │ -c core.quotepath=false, …subcommand]
67
- │ env = parent − removed git keys + forced deterministic values
68
-
69
- git ──byte-capped stdout──▶ parsers (--format + %x1f, numstat,
70
- porcelain) ──▶ structured result
71
- ```
72
-
73
- ## 4. Trust boundaries
74
-
75
- - **Repository content is untrusted data.** Commit messages, branch names,
76
- patches and file content are returned as data; every tool description
77
- tells the model so. The plugin never parses untrusted output into
78
- behavior.
79
- - **Repository configuration is untrusted.** `.git/config` and
80
- `.gitattributes` of the inspected repo may point diff/textconv/fsmonitor
81
- at executables; the hardening flags disable all three paths, and §9
82
- proves it.
83
- - **The parent environment is untrusted.** Ambient git redirection keys are
84
- stripped per invocation (§1.8).
85
-
86
- ## 5. Configuration
87
-
88
- See the README configuration table. All limits are clamped into safe
89
- corridors by `resolveGitReadonlyConfig`; `enabled: false` removes the tool
90
- surface entirely instead of registering inert tools.
91
-
92
- ## 6. Hardening invariants (runner)
93
-
94
- 1. argv array only; no `shell:`; `windowsHide`; stdin ignored.
95
- 2. Prefix flags on every invocation: `--no-pager`, `-c core.fsmonitor=false`,
96
- `-c core.quotepath=false`.
97
- 3. Diff-producing commands add `--no-ext-diff --no-textconv --no-color`
98
- (`dsh_git_show`, and `dsh_git_history` because pickaxe runs the diff
99
- machinery); `dsh_git_blame` adds `--no-textconv` (blame honors textconv
100
- by default).
101
- 4. Environment: `REMOVED_ENV_KEYS` stripped; `LC_ALL=C`,
102
- `GIT_OPTIONAL_LOCKS=0`, `GIT_TERMINAL_PROMPT=0`, `GIT_CONFIG_NOSYSTEM=1`,
103
- `GIT_PAGER=cat`, `PAGER=cat` forced.
104
- 5. The child is killed at the byte cap or the timeout (with SIGKILL
105
- escalation) and the result reports `truncated` / `timedOut`.
106
-
107
- ## 7. Lifecycle
108
-
109
- The plugin is stateless: `apply` resolves config and registers four tools;
110
- registrations are collected by the Cordis plugin scope on dispose/reload.
111
- Nothing is stored on disk beyond plugin log records (tool names, exit
112
- codes, durations, truncation flags — never content).
113
-
114
- ## 8. Scope
115
-
116
- **Included:** the four provenance tools, validation, hardening, structured
117
- bounded output, typed errors, mutation tests.
118
-
119
- **Deferred (deliberately):**
120
-
121
- - a generic `git(command)` tool or shell escape hatch — the entire point is
122
- to not have one;
123
- - write operations (commit, checkout, stash, config, worktree, hooks);
124
- - network operations (fetch, push, clone, submodule) — absent by design;
125
- - OS-level confinement (mount namespaces, bubblewrap) — the tools are
126
- read-only by construction; an OS sandbox would strengthen the promise but
127
- is platform-dependent (Linux-only in current harness sandboxes) and
128
- unnecessary for the contract above;
129
- - `dsh-session-scope` integration — focused scopes do not confine child
130
- processes; if a scoped deployment needs subtree-fenced history, the
131
- session-scope host API should grow a `visibleRoots` seam first.
132
-
133
- ## 9. Mutation test contract
134
-
135
- The suite in `tests/mutation.test.ts` is normative for regressions:
136
-
137
- - snapshot (work tree + `.git` minus reflogs) before/after every tool call,
138
- twice in sequence, must be byte-identical;
139
- - a repository whose `.git/config` wires `diff.external`, a textconv driver
140
- and `core.fsmonitor` to a marker-writing helper must never produce the
141
- marker from any tool call, while still returning correct output;
142
- - poisoned `GIT_DIR` / `GIT_EXTERNAL_DIFF` / `GIT_INDEX_FILE` /
143
- `GIT_WORK_TREE` / `GIT_OBJECT_DIRECTORY` in the parent environment must
144
- not redirect reads;
145
- - `../` traversal in any path argument must be rejected before spawning;
146
- - an oversized patch must be truncated and flagged;
147
- - missing session cwd / non-repository cwd must fail closed.
148
-
149
- ## 10. Implementation status
150
-
151
- | Area | Status |
152
- | --- | --- |
153
- | `dsh_git_context` | Implemented |
154
- | `dsh_git_history` | Implemented |
155
- | `dsh_git_show` | Implemented |
156
- | `dsh_git_blame` | Implemented |
157
- | Runner hardening (argv/env/caps/kill) | Implemented |
158
- | Mutation test contract (§9) | Implemented |
159
- | OS-level confinement | Deferred (see §8) |
160
- | session-scope subtree fencing | Deferred (see §8) |