Repository navigation
Commit a63539c
Run every test and script Git command with an allowlisted environment (#82)
* Open a stale item's comparison when the answer that makes it stale arrives after it was selected
The review page chose "Since approval" or "Full change" once, in select(),
from the data present at the click. When the reviewer selected P1 while an
Assign request was still in flight, P1 was still approved in that data, so the
page chose Full change. The Assign answer then made P1 stale and re-rendered
its stale reasons, but it kept the earlier choice, so the "At approval"
comparison never appeared. This is the intermittent failure of
review.spec.ts "reviews real changes, persists approval and conversation, and
assigns foreign code" (CI run 36498484408, attempt 1).
The page now stores only an explicit toggle, keyed to the item and to the
stale state it was made on (reasons, current segments and plan item). With no
matching choice, a stale item always opens in Since approval, whatever answer
made it stale. An explicit choice survives answers that leave that state
unchanged, and ends when the item's code or plan changes or the reviewer
selects another item.
The new browser test holds the Assign answer with a promise, selects P1 while
it is still approved, releases the answer, and asserts the comparison and the
stored stale state. It fails on the previous app.js at the race step.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Key the explicit view choice to every segment field the approval fingerprint covers
The stale-state key used only path, operation and content, but
core/approvals.ts also counts oldPath, kind, context and owners as a change.
Moving unchanged text to another function changes only context and makes the
item stale, yet the key stayed the same, so an earlier "Full change" choice
hid the comparison for the new state. The key now uses the same fields.
The new browser test changes context, owners and oldPath one at a time in the
review answer and expects the comparison each time. It fails on the previous
key, and dropping any one of the three fields from the key fails it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Name each stale state on the server instead of mirroring staleness in the page
The page kept an explicit view choice by building its own key from the
item's segments, reasons and plan item. That copy of the server's staleness
rules missed inputs: the approval the comparison is drawn against, ambiguous
segments the item owns, its dependencies' stale states, and the context of a
replaced head after a queue attempt. In each case an old choice could apply
to a stale state the reviewer had not seen.
ReviewService.load() now returns staleKey for each stale item: a hash of the
saved approval, the current approval fingerprint (fingerprint() is now
exported from core/approvals.ts), the ambiguous segments it owns, its
dependencies' stale keys, and the queue-replacement context when it applies.
The page compares only this key.
Tests:
- test/review.test.ts: three unit tests cover a dependency change with the
same reasons, re-approval while still stale, re-approval followed by an
ambiguous change with identical own segments and reasons, an ambiguous
change on a still-stale item, and a second replaced head. Removing any one
of the five key inputs fails a test.
- The browser test that edited segment fields is replaced by one that
changes only staleKey in the answer; it fails if the page ignores the key.
- The "explicit choice survives Refresh" step now waits until the Refresh
answer is rendered, so it fails if Refresh resets the choice.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Key a stale item's ambiguous segments by every field an approval covers
The stale key identified the ambiguous segments an item owns by their choice
keys, which leave out context and owners. An ambiguous segment that moved to
another function or gained an owner therefore kept the same stale key, so an
earlier "Full change" choice survived the new stale state.
core/approvals.ts now has reviewedSegment(), the segment fields an approval
covers, used by fingerprint() and by the ambiguous part of the stale key.
The ambiguous stale-key test now has P3 edit the shared line and restore
its text, so the segment keeps its choice key but gains an owner; the key
must change. Using only choice keys fails that step. The two longer
stale-key tests get the 30 s limit other multi-commit tests in this file use.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Hash each ambiguous segment once per load in the stale key
The stale key serialized an ambiguous segment's full reviewed fields once for
every stale item that owns it. A large segment shared by many items made each
synchronous load() repeat that work per owner.
load() now hashes reviewedSegment() once per segment, memoized by segment key,
and each owner's stale key includes that digest. The fields stay the ones an
approval covers, so a change in context or owners still gives a new key.
The ambiguous stale-key test now approves P1, P2 and P3 first, so the shared
line belongs to three stale items, and counts reviewedSegment() calls from
load() through a passthrough mock: one per segment. The previous per-owner
form fails that count, and leaving owners out of the digest fails the owners
step.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Run this PR's test Git commands with the hardened fixture invocation
The Git commands added by this PR's tests inherited the caller's environment
and user config and only disabled hooks. An inherited GIT_DIR or
GIT_WORK_TREE could redirect their commits outside the fixture, and user
config could change their behaviour, against the AGENTS.md rule on
subprocess environments and hardened Git.
test/fixtures/git.ts adds fixtureGit(): an allowlisted environment (PATH and
the Git hardening variables only), no user or system config, no hooks, no
replace objects, no lazy fetch and no network protocols, as git/history.ts
does. The new stale-key unit tests and the in-flight browser test use it.
test/fixture-git.test.ts sets GIT_DIR, GIT_WORK_TREE, GIT_CONFIG_GLOBAL and
GIT_AUTHOR_NAME to point elsewhere and checks that a commit stays in the
fixture with the fixture's identity. Passing process.env through fails it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Run every test and script Git command with an allowlisted environment
Test Git helpers in review, browser, agent, store, history, plant and
question tests inherited process.env. They now use fixtureGit().
scripts/demo.ts and scripts/plant.ts removed only GIT_* names from the
inherited environment. Git still read HOME and XDG_CONFIG_HOME, so a
user's git/ignore could make plant's `git add -A` skip the undeclared
plant while sealed.json recorded it. Both scripts now pass only PATH and
the hardening variables, and add --no-pager, --no-replace-objects and
protocol.allow=never. Plant allows the file protocol for its one local
clone only, as git/clone.ts does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Remove a saved vitest report committed by mistake, and ignore .vitest/
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Build the fixture Git invocation from the scripts' hardened options and environment
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>1 parent f53227c commit a63539c
19 files changed
Lines changed: 89 additions & 77 deletions
File tree
- scripts
- test
- browser
- fixtures
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| 9 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
| 9 | + | |
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
38 | | - | |
| 38 | + | |
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
2 | | - | |
3 | | - | |
4 | | - | |
5 | | - | |
6 | | - | |
7 | | - | |
8 | | - | |
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
9 | 11 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
45 | | - | |
46 | | - | |
| 45 | + | |
| 46 | + | |
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
| |||
54 | 54 | | |
55 | 55 | | |
56 | 56 | | |
57 | | - | |
| 57 | + | |
58 | 58 | | |
59 | 59 | | |
60 | 60 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | 5 | | |
| |||
21 | 22 | | |
22 | 23 | | |
23 | 24 | | |
24 | | - | |
25 | | - | |
| 25 | + | |
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | 5 | | |
| |||
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
18 | | - | |
19 | | - | |
| 19 | + | |
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | 5 | | |
| |||
30 | 31 | | |
31 | 32 | | |
32 | 33 | | |
33 | | - | |
34 | | - | |
| 34 | + | |
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | | - | |
14 | | - | |
| 13 | + | |
15 | 14 | | |
16 | 15 | | |
17 | 16 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| |||
128 | 128 | | |
129 | 129 | | |
130 | 130 | | |
131 | | - | |
132 | | - | |
| 131 | + | |
133 | 132 | | |
134 | 133 | | |
135 | 134 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
3 | 4 | | |
4 | 5 | | |
5 | 6 | | |
| |||
23 | 24 | | |
24 | 25 | | |
25 | 26 | | |
26 | | - | |
27 | | - | |
| 27 | + | |
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| |||
0 commit comments